diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-07 13:12:05 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:02:59 +0000 |
commit | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (patch) | |
tree | f6af110909c79b2759136554f1143d8b0572af0a /chromium/cc | |
parent | 7d2c5d177e9813077a621df8d18c0deda73099b3 (diff) | |
download | qtwebengine-chromium-33fc33aa94d4add0878ec30dc818e34e1dd3cc2a.tar.gz |
BASELINE: Update Chromium to 104.0.5112.120
Change-Id: I5d2726c2ab018d75d055739b6ba64317904f05bb
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438935
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
206 files changed, 4775 insertions, 2844 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn index 091ec28180f..e52844d44a8 100644 --- a/chromium/cc/BUILD.gn +++ b/chromium/cc/BUILD.gn @@ -178,10 +178,14 @@ cc_component("cc") { "metrics/compositor_frame_reporting_controller.h", "metrics/compositor_timing_history.cc", "metrics/compositor_timing_history.h", + "metrics/custom_metrics_recorder.cc", + "metrics/custom_metrics_recorder.h", "metrics/dropped_frame_counter.cc", "metrics/dropped_frame_counter.h", "metrics/event_latency_tracing_recorder.cc", "metrics/event_latency_tracing_recorder.h", + "metrics/event_latency_tracker.cc", + "metrics/event_latency_tracker.h", "metrics/event_metrics.cc", "metrics/event_metrics.h", "metrics/events_metrics_manager.cc", @@ -905,14 +909,15 @@ cc_test("cc_unittests") { } if (is_fuchsia) { - use_cfv2 = false - additional_manifest_fragments = [ - "//build/config/fuchsia/test/font_capabilities.test-cmx", + use_cfv1 = false - # TODO(crbug.com/1185811): Figure out why jit_capabilities is needed. - "//build/config/fuchsia/test/jit_capabilities.test-cmx", + # TODO(https://crbug.com/1185811): Investigate removing the requirement for + # job_policy_ambient_mark_vmo_exec for the sake of V8's allocator in tests. + test_runner_shard = "//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml" - "//build/config/fuchsia/test/vulkan_capabilities.test-cmx", + additional_manifest_fragments = [ + "//build/config/fuchsia/test/fonts.shard.test-cml", + "//third_party/fuchsia-sdk/sdk/pkg/vulkan/client.shard.cml", ] } @@ -993,9 +998,6 @@ if (is_android) { # Right now, this only includes the Java switches. But if we need more Java # files, they should be added here as necessary. srcjar_deps = [ ":cc_android_java_enums_srcjar" ] - deps = [ - "//base:base_java", - "//third_party/androidx:androidx_annotation_annotation_java", - ] + deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ] } } diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS index 55466a8233c..ae56e384462 100644 --- a/chromium/cc/DEPS +++ b/chromium/cc/DEPS @@ -21,7 +21,6 @@ include_rules = [ "+gpu/command_buffer/common/shared_image_trace_utils.h", "+gpu/command_buffer/common/shared_image_usage.h", "+gpu/command_buffer/common/sync_token.h", - "+gpu/command_buffer/common/texture_in_use_response.h", "+gpu/config/gpu_feature_info.h", "+gpu/config/gpu_finch_features.h", "+gpu/config/gpu_info.h", diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS index 172a0c0989d..e695df24414 100644 --- a/chromium/cc/OWNERS +++ b/chromium/cc/OWNERS @@ -15,6 +15,7 @@ ccameron@chromium.org # scheduling / begin frames sunnyps@chromium.org +szager@chromium.org # tiles, tile management, and raster work vmpstr@chromium.org @@ -28,7 +29,6 @@ flackr@chromium.org # property trees chrishtr@chromium.org -weiliangc@chromium.org pdr@chromium.org wangxianzhu@chromium.org diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc index d64a61535dd..18926560de3 100644 --- a/chromium/cc/animation/animation_host.cc +++ b/chromium/cc/animation/animation_host.cc @@ -154,6 +154,15 @@ void AnimationHost::SetHasSmilAnimation(bool has_smil_animation) { has_smil_animation_.Write(*this) = has_smil_animation; } +bool AnimationHost::HasSharedElementTransition() const { + return has_shared_element_transition_.Read(*this); +} + +void AnimationHost::SetHasSharedElementTransition( + bool has_shared_element_transition) { + has_shared_element_transition_.Write(*this) = has_shared_element_transition; +} + void AnimationHost::SetCurrentFrameHadRaf(bool current_frame_had_raf) { current_frame_had_raf_.Write(*this) = current_frame_had_raf; } @@ -179,6 +188,7 @@ void AnimationHost::RemoveElementId(ElementId element_id) { scoped_refptr<ElementAnimations> element_animations = GetElementAnimationsForElementId(element_id); if (element_animations) { + DCHECK(!element_animations->HasTickingKeyframeEffect()); element_animations->RemoveKeyframeEffects(); } } @@ -187,6 +197,26 @@ void AnimationHost::RegisterAnimationForElement(ElementId element_id, Animation* animation) { DCHECK(element_id); DCHECK(animation); +#if DCHECK_IS_ON() + for (const auto& keyframe_model : + animation->keyframe_effect()->keyframe_models()) { + KeyframeModel* cc_keyframe_model = + KeyframeModel::ToCcKeyframeModel(keyframe_model.get()); + ElementId model_element_id = cc_keyframe_model->element_id() + ? cc_keyframe_model->element_id() + : element_id; + DCHECK(cc_keyframe_model->affects_active_elements() || + cc_keyframe_model->affects_pending_elements()); + DCHECK(!cc_keyframe_model->affects_active_elements() || + mutator_host_client()->IsElementInPropertyTrees( + model_element_id, ElementListType::ACTIVE)); + // Test thread_instance_ because LayerTreeHost has no pending tree. + DCHECK(thread_instance_ == ThreadInstance::MAIN || + !cc_keyframe_model->affects_pending_elements() || + mutator_host_client()->IsElementInPropertyTrees( + model_element_id, ElementListType::PENDING)); + } +#endif scoped_refptr<ElementAnimations> element_animations = GetElementAnimationsForElementId(element_id); @@ -307,6 +337,7 @@ void AnimationHost::PushPropertiesTo(MutatorHost* mutator_host_impl, host_impl->SetHasCanvasInvalidation(HasCanvasInvalidation()); host_impl->SetHasInlineStyleMutation(HasJSAnimation()); host_impl->SetHasSmilAnimation(HasSmilAnimation()); + host_impl->SetHasSharedElementTransition(HasSharedElementTransition()); if (needs_push_properties()) { needs_push_properties_.Write(*this) = false; @@ -609,81 +640,23 @@ bool AnimationHost::ScrollOffsetAnimationWasInterrupted( : false; } -bool AnimationHost::IsAnimatingFilterProperty(ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->IsCurrentlyAnimatingProperty( - TargetProperty::FILTER, list_type) - : false; -} - -bool AnimationHost::IsAnimatingBackdropFilterProperty( - ElementId element_id, - ElementListType list_type) const { +bool AnimationHost::IsAnimatingProperty(ElementId element_id, + ElementListType list_type, + TargetProperty::Type property) const { auto element_animations = GetElementAnimationsForElementId(element_id); return element_animations ? element_animations->IsCurrentlyAnimatingProperty( - TargetProperty::BACKDROP_FILTER, list_type) + property, list_type) : false; } -bool AnimationHost::IsAnimatingOpacityProperty( - ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->IsCurrentlyAnimatingProperty( - TargetProperty::OPACITY, list_type) - : false; -} - -bool AnimationHost::IsAnimatingTransformProperty( - ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->IsCurrentlyAnimatingProperty( - TargetProperty::TRANSFORM, list_type) - : false; -} - -bool AnimationHost::HasPotentiallyRunningFilterAnimation( +bool AnimationHost::HasPotentiallyRunningAnimationForProperty( ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->IsPotentiallyAnimatingProperty( - TargetProperty::FILTER, list_type) - : 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 { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->IsPotentiallyAnimatingProperty( - TargetProperty::OPACITY, list_type) - : false; -} - -bool AnimationHost::HasPotentiallyRunningTransformAnimation( - ElementId element_id, - ElementListType list_type) const { + ElementListType list_type, + TargetProperty::Type property) const { auto element_animations = GetElementAnimationsForElementId(element_id); return element_animations - ? element_animations->IsPotentiallyAnimatingProperty( - TargetProperty::TRANSFORM, list_type) + ? element_animations->IsPotentiallyAnimatingProperty(property, + list_type) : false; } @@ -694,7 +667,8 @@ bool AnimationHost::HasAnyAnimationTargetingProperty( if (!element_animations) return false; - return element_animations->HasAnyAnimationTargetingProperty(property); + return element_animations->HasAnyAnimationTargetingProperty(property, + element_id); } bool AnimationHost::AnimationsPreserveAxisAlignment( @@ -708,7 +682,7 @@ bool AnimationHost::AnimationsPreserveAxisAlignment( float AnimationHost::MaximumScale(ElementId element_id, ElementListType list_type) const { if (auto element_animations = GetElementAnimationsForElementId(element_id)) - return element_animations->MaximumScale(list_type); + return element_animations->MaximumScale(element_id, list_type); return kInvalidScale; } diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h index 08a38b355ad..402c54f77be 100644 --- a/chromium/cc/animation/animation_host.h +++ b/chromium/cc/animation/animation_host.h @@ -136,28 +136,14 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, bool ScrollOffsetAnimationWasInterrupted(ElementId element_id) const override; - 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, - ElementListType list_type) const override; + bool IsAnimatingProperty(ElementId element_id, + ElementListType list_type, + TargetProperty::Type property) const override; - bool HasPotentiallyRunningFilterAnimation( - ElementId element_id, - ElementListType list_type) const override; - bool HasPotentiallyRunningBackdropFilterAnimation( - ElementId element_id, - ElementListType list_type) const override; - bool HasPotentiallyRunningOpacityAnimation( + bool HasPotentiallyRunningAnimationForProperty( ElementId element_id, - ElementListType list_type) const override; - bool HasPotentiallyRunningTransformAnimation( - ElementId element_id, - ElementListType list_type) const override; + ElementListType list_type, + TargetProperty::Type property) const override; bool HasAnyAnimationTargetingProperty( ElementId element_id, @@ -225,6 +211,7 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, bool HasCanvasInvalidation() const override; bool HasJSAnimation() const override; bool HasSmilAnimation() const override; + bool HasSharedElementTransition() const override; // Starts/stops throughput tracking represented by |sequence_id|. void StartThroughputTracking(TrackedAnimationSequenceId sequence_id); @@ -234,6 +221,7 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, void SetHasCanvasInvalidation(bool has_canvas_invalidation); void SetHasInlineStyleMutation(bool has_inline_style_mutation); void SetHasSmilAnimation(bool has_svg_smil_animation); + void SetHasSharedElementTransition(bool hash_shared_element_transition); void SetCurrentFrameHadRaf(bool current_frame_had_raf); void SetNextFrameHasPendingRaf(bool next_frame_has_pending_raf); @@ -298,6 +286,7 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, ProtectedSequenceReadable<bool> has_canvas_invalidation_{false}; ProtectedSequenceReadable<bool> has_inline_style_mutation_{false}; ProtectedSequenceReadable<bool> has_smil_animation_{false}; + ProtectedSequenceReadable<bool> has_shared_element_transition_{false}; ProtectedSequenceWritable<PendingThroughputTrackerInfos> pending_throughput_tracker_infos_; diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc index 0454c9b9cb3..42203ab3fb1 100644 --- a/chromium/cc/animation/animation_unittest.cc +++ b/chromium/cc/animation/animation_unittest.cc @@ -428,10 +428,12 @@ TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) { EXPECT_TRUE(animation_->keyframe_effect()->element_animations()); EXPECT_FALSE(animation_->keyframe_effect() ->element_animations() - ->HasAnyAnimationTargetingProperty(TargetProperty::FILTER)); + ->HasAnyAnimationTargetingProperty(TargetProperty::FILTER, + element_id_)); EXPECT_TRUE(animation_->keyframe_effect() ->element_animations() - ->HasAnyAnimationTargetingProperty(TargetProperty::OPACITY)); + ->HasAnyAnimationTargetingProperty(TargetProperty::OPACITY, + element_id_)); EXPECT_TRUE(animation_->keyframe_effect()->needs_push_properties()); host_->PushPropertiesTo(host_impl_, client_.GetPropertyTrees()); @@ -552,7 +554,7 @@ TEST_F(AnimationTest, ToString) { EXPECT_EQ( base::StringPrintf("Animation{id=%d, element_id=%s, " "keyframe_models=[KeyframeModel{id=42, " - "group=73, target_property_type=1, " + "group=73, target_property_type=4, " "custom_property_name=, native_property_type=2, " "run_state=WAITING_FOR_TARGET_AVAILABILITY, " "element_id=(0)}]}", @@ -565,10 +567,10 @@ TEST_F(AnimationTest, ToString) { EXPECT_EQ(base::StringPrintf( "Animation{id=%d, element_id=%s, " "keyframe_models=[KeyframeModel{id=42, " - "group=73, target_property_type=1, custom_property_name=, " + "group=73, target_property_type=4, custom_property_name=, " "native_property_type=2, " "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}, " - "KeyframeModel{id=45, group=76, target_property_type=5, " + "KeyframeModel{id=45, group=76, target_property_type=8, " "custom_property_name=, native_property_type=2, " "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}]}", animation_->id(), element_id_.ToString().c_str()), diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc index 753e500cf69..153e0997a4f 100644 --- a/chromium/cc/animation/element_animations.cc +++ b/chromium/cc/animation/element_animations.cc @@ -60,8 +60,10 @@ ElementAnimations::ElementAnimations(AnimationHost* host, ElementId element_id) : animation_host_(host), element_id_(element_id), needs_push_properties_(false), - active_maximum_scale_(kInvalidScale), - pending_maximum_scale_(kInvalidScale) { + transform_property_active_maximum_scale_(kInvalidScale), + transform_property_pending_maximum_scale_(kInvalidScale), + scale_property_active_maximum_scale_(kInvalidScale), + scale_property_pending_maximum_scale_(kInvalidScale) { InitAffectedElementTypes(); } @@ -77,6 +79,9 @@ void ElementAnimations::InitAffectedElementTypes() { gfx::TargetProperties ElementAnimations::GetPropertiesMaskForAnimationState() { gfx::TargetProperties properties; properties[TargetProperty::TRANSFORM] = true; + properties[TargetProperty::SCALE] = true; + properties[TargetProperty::ROTATE] = true; + properties[TargetProperty::TRANSLATE] = true; properties[TargetProperty::OPACITY] = true; properties[TargetProperty::FILTER] = true; properties[TargetProperty::BACKDROP_FILTER] = true; @@ -158,11 +163,12 @@ bool ElementAnimations::AnimationsPreserveAxisAlignment() const { return true; } -float ElementAnimations::MaximumScale(ElementListType list_type) const { +float ElementAnimations::MaximumScale(ElementId element_id, + ElementListType list_type) const { float maximum_scale = kInvalidScale; for (auto& keyframe_effect : keyframe_effects_list_) { - maximum_scale = - std::max(maximum_scale, keyframe_effect.MaximumScale(list_type)); + maximum_scale = std::max( + maximum_scale, keyframe_effect.MaximumScale(element_id, list_type)); } return maximum_scale; } @@ -265,11 +271,34 @@ void ElementAnimations::InitClientAnimationState() { // (instead of only changed) recalculated current states to the client. pending_state_.Clear(); active_state_.Clear(); - active_maximum_scale_ = kInvalidScale; - pending_maximum_scale_ = kInvalidScale; + transform_property_active_maximum_scale_ = kInvalidScale; + transform_property_pending_maximum_scale_ = kInvalidScale; + scale_property_active_maximum_scale_ = kInvalidScale; + scale_property_pending_maximum_scale_ = kInvalidScale; UpdateClientAnimationState(); } +void ElementAnimations::UpdateMaximumScale(ElementId element_id, + ElementListType list_type, + float* cached_scale) { + if (element_id) { + float maximum_scale = MaximumScale(element_id, list_type); + if (*cached_scale != maximum_scale) { + animation_host_->mutator_host_client()->MaximumScaleChanged( + element_id, list_type, maximum_scale); + *cached_scale = maximum_scale; + } + } else { + *cached_scale = kInvalidScale; + } +} + +#if DCHECK_IS_ON() +static inline bool IsInvalidOrOne(float scale) { + return scale == kInvalidScale || scale == 1.f; +} +#endif + void ElementAnimations::UpdateClientAnimationState() { if (!element_id()) return; @@ -311,6 +340,11 @@ void ElementAnimations::UpdateClientAnimationState() { PropertyToElementIdMap element_id_map = GetPropertyToElementIdMap(); ElementId transform_element_id = element_id_map[TargetProperty::TRANSFORM]; + ElementId scale_element_id = element_id_map[TargetProperty::SCALE]; +#if DCHECK_IS_ON() + ElementId rotate_element_id = element_id_map[TargetProperty::ROTATE]; + ElementId translate_element_id = element_id_map[TargetProperty::TRANSLATE]; +#endif if (prev_active != active_state_) { PropertyAnimationState diff_active = prev_active ^ active_state_; @@ -318,14 +352,16 @@ void ElementAnimations::UpdateClientAnimationState() { element_id_map, ElementListType::ACTIVE, diff_active, active_state_); } - float maximum_scale = transform_element_id - ? MaximumScale(ElementListType::ACTIVE) - : kInvalidScale; - if (maximum_scale != active_maximum_scale_) { - animation_host_->mutator_host_client()->MaximumScaleChanged( - transform_element_id, ElementListType::ACTIVE, maximum_scale); - active_maximum_scale_ = maximum_scale; - } + UpdateMaximumScale(transform_element_id, ElementListType::ACTIVE, + &transform_property_active_maximum_scale_); + UpdateMaximumScale(scale_element_id, ElementListType::ACTIVE, + &scale_property_active_maximum_scale_); +#if DCHECK_IS_ON() + DCHECK( + IsInvalidOrOne(MaximumScale(rotate_element_id, ElementListType::ACTIVE))); + DCHECK(IsInvalidOrOne( + MaximumScale(translate_element_id, ElementListType::ACTIVE))); +#endif if (prev_pending != pending_state_) { PropertyAnimationState diff_pending = prev_pending ^ pending_state_; @@ -333,13 +369,16 @@ void ElementAnimations::UpdateClientAnimationState() { element_id_map, ElementListType::PENDING, diff_pending, pending_state_); } - maximum_scale = transform_element_id ? MaximumScale(ElementListType::PENDING) - : kInvalidScale; - if (maximum_scale != pending_maximum_scale_) { - animation_host_->mutator_host_client()->MaximumScaleChanged( - transform_element_id, ElementListType::PENDING, maximum_scale); - pending_maximum_scale_ = maximum_scale; - } + UpdateMaximumScale(transform_element_id, ElementListType::PENDING, + &transform_property_pending_maximum_scale_); + UpdateMaximumScale(scale_element_id, ElementListType::PENDING, + &scale_property_pending_maximum_scale_); +#if DCHECK_IS_ON() + DCHECK(IsInvalidOrOne( + MaximumScale(rotate_element_id, ElementListType::PENDING))); + DCHECK(IsInvalidOrOne( + MaximumScale(translate_element_id, ElementListType::PENDING))); +#endif } void ElementAnimations::AttachToCurve(gfx::AnimationCurve* c) { @@ -386,10 +425,12 @@ bool ElementAnimations::HasAnyKeyframeModel() const { } bool ElementAnimations::HasAnyAnimationTargetingProperty( - TargetProperty::Type property) const { + TargetProperty::Type property, + ElementId element_id) const { for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.GetKeyframeModel(property)) - return true; + if (gfx::KeyframeModel* model = keyframe_effect.GetKeyframeModel(property)) + if (CalculateTargetElementId(this, model) == element_id) + return true; } return false; } diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h index 10e25656f14..bdede8ebe86 100644 --- a/chromium/cc/animation/element_animations.h +++ b/chromium/cc/animation/element_animations.h @@ -80,7 +80,8 @@ class CC_ANIMATION_EXPORT ElementAnimations // Returns true if there are any KeyframeModels at all to process. bool HasAnyKeyframeModel() const; - bool HasAnyAnimationTargetingProperty(TargetProperty::Type property) const; + bool HasAnyAnimationTargetingProperty(TargetProperty::Type property, + ElementId element_id) const; // Returns true if there is an animation that is either currently animating // the given property or scheduled to animate this property in the future, and @@ -98,7 +99,7 @@ class CC_ANIMATION_EXPORT ElementAnimations // Returns the maximum scale along any dimension at any destination in active // scale animations, or kInvalidScale if there is no active transform // animation or the scale cannot be computed. - float MaximumScale(ElementListType list_type) const; + float MaximumScale(ElementId element_id, ElementListType list_type) const; bool ScrollOffsetAnimationWasInterrupted() const; @@ -187,6 +188,10 @@ class CC_ANIMATION_EXPORT ElementAnimations static gfx::TargetProperties GetPropertiesMaskForAnimationState(); + void UpdateMaximumScale(ElementId element_id, + ElementListType list_type, + float* cached_scale); + void UpdateKeyframeEffectsTickingState() const; void RemoveKeyframeEffectsFromTicking() const; @@ -203,8 +208,10 @@ class CC_ANIMATION_EXPORT ElementAnimations PropertyAnimationState active_state_; PropertyAnimationState pending_state_; - float active_maximum_scale_; - float pending_maximum_scale_; + float transform_property_active_maximum_scale_; + float transform_property_pending_maximum_scale_; + float scale_property_active_maximum_scale_; + float scale_property_pending_maximum_scale_; }; } // namespace cc diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc index 021004ae4c3..63d3e3d442b 100644 --- a/chromium/cc/animation/element_animations_unittest.cc +++ b/chromium/cc/animation/element_animations_unittest.cc @@ -695,6 +695,66 @@ TEST_F(ElementAnimationsTest, AnimationsAreDeleted) { EXPECT_FALSE(animation_impl_->keyframe_effect()->has_any_keyframe_model()); } +// Test an animation that finishes on impl but is deleted on main before the +// event is received. https://crbug.com/1325393. +TEST_F(ElementAnimationsTest, AnimationFinishedOnImplDeletedOnMain) { + CreateTestLayer(true, false); + AttachTimelineAnimationLayer(); + CreateImplTimelineAndAnimation(); + + auto events = CreateEventsForTesting(); + + AddOpacityTransitionToAnimation(animation_.get(), 1.0, 0.0f, 1.0f, false); + animation_->Tick(kInitialTickTime); + animation_->UpdateState(true, nullptr); + EXPECT_TRUE(animation_->keyframe_effect()->needs_push_properties()); + + PushProperties(); + EXPECT_FALSE(animation_->keyframe_effect()->needs_push_properties()); + + animation_impl_->ActivateKeyframeModels(); + + animation_impl_->Tick(kInitialTickTime + base::Milliseconds(500)); + animation_impl_->UpdateState(true, events.get()); + + // There should be a STARTED event for the animation. + EXPECT_EQ(1u, events->events_.size()); + EXPECT_EQ(AnimationEvent::STARTED, events->events_[0].type); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); + + events = CreateEventsForTesting(); + animation_impl_->Tick(kInitialTickTime + base::Milliseconds(2000)); + animation_impl_->UpdateState(true, events.get()); + + EXPECT_TRUE(host_impl_->needs_push_properties()); + + // There should be a FINISHED event for the animation. + EXPECT_EQ(1u, events->events_.size()); + EXPECT_EQ(AnimationEvent::FINISHED, events->events_[0].type); + + // Before the FINISHED event is received, main aborts the keyframe + // and detaches the element. + animation_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, false); + PushProperties(); + animation_->DetachElement(); + // Expect no keyframe model. + EXPECT_FALSE(animation_->keyframe_effect()->has_any_keyframe_model()); + + // Then we dispatch the FINISHED event. + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); + + EXPECT_TRUE(host_->needs_push_properties()); + + PushProperties(); + + // Both animations should now have deleted the animation. The impl animations + // should have deleted the animation even though activation has not occurred, + // since the animation was already waiting for deletion when + // PushPropertiesTo was called. + EXPECT_FALSE(animation_->keyframe_effect()->has_any_keyframe_model()); + EXPECT_FALSE(animation_impl_->keyframe_effect()->has_any_keyframe_model()); +} + // Tests that transitioning opacity from 0 to 1 works as expected. static std::unique_ptr<KeyframeModel> CreateKeyframeModel( @@ -2174,10 +2234,10 @@ TEST_F(ElementAnimationsTest, MaximumAnimationScaleNotScaled) { AttachTimelineAnimationLayer(); CreateImplTimelineAndAnimation(); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); animation_impl_->AddKeyframeModel( CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>( @@ -2185,10 +2245,10 @@ TEST_F(ElementAnimationsTest, MaximumAnimationScaleNotScaled) { 1, TargetProperty::OPACITY)); // Opacity animations aren't non-translation transforms. - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1( gfx::KeyframedTransformAnimationCurve::Create()); @@ -2206,10 +2266,10 @@ TEST_F(ElementAnimationsTest, MaximumAnimationScaleNotScaled) { animation_impl_->AddKeyframeModel(std::move(keyframe_model)); // The only transform animation we've added is a translation. - EXPECT_EQ(1.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(1.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(1.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(1.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); } TEST_F(ElementAnimationsTest, MaximumAnimationNonCalculatableScale) { @@ -2236,10 +2296,10 @@ TEST_F(ElementAnimationsTest, MaximumAnimationNonCalculatableScale) { // All keyframes have perspective, so the ElementAnimations' scale is not // calculatable. - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); } TEST_F(ElementAnimationsTest, MaximumAnimationPartialNonCalculatableScale) { @@ -2265,10 +2325,10 @@ TEST_F(ElementAnimationsTest, MaximumAnimationPartialNonCalculatableScale) { // Though some keyframes have perspective and the scale is not calculatable, // we use the other keyframes to calculate the ElementAnimations' scale. - EXPECT_EQ(2.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(2.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(2.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(2.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); } TEST_F(ElementAnimationsTest, MaximumScale) { @@ -2293,16 +2353,16 @@ TEST_F(ElementAnimationsTest, MaximumScale) { keyframe_model->set_affects_active_elements(false); animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - EXPECT_EQ(5.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(5.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); animation_impl_->ActivateKeyframeModels(); - EXPECT_EQ(5.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(5.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(5.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(5.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve2( gfx::KeyframedTransformAnimationCurve::Create()); @@ -2344,25 +2404,25 @@ TEST_F(ElementAnimationsTest, MaximumScale) { keyframe_model->set_affects_active_elements(false); animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(kInvalidScale, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(kInvalidScale, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); animation_impl_->ActivateKeyframeModels(); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); animation_impl_->keyframe_effect()->GetKeyframeModelById(2)->SetRunState( KeyframeModel::FINISHED, TicksFromSecondsF(0.0)); // Only unfinished animations should be considered by MaximumAnimationScale. - EXPECT_EQ(5.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(5.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(5.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(5.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); } TEST_F(ElementAnimationsTest, MaximumAnimationScaleWithDirection) { @@ -2391,61 +2451,61 @@ TEST_F(ElementAnimationsTest, MaximumAnimationScaleWithDirection) { // NORMAL direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::NORMAL); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // ALTERNATE direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // REVERSE direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // ALTERNATE reverse direction. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); keyframe_model->set_playback_rate(-1.0); // NORMAL direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::NORMAL); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // ALTERNATE direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // REVERSE direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); // ALTERNATE reverse direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::PENDING)); - EXPECT_EQ(6.f, - element_animations_impl_->MaximumScale(ElementListType::ACTIVE)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::PENDING)); + EXPECT_EQ(6.f, element_animations_impl_->MaximumScale( + element_id_, ElementListType::ACTIVE)); } TEST_F(ElementAnimationsTest, NewlyPushedAnimationWaitsForActivation) { diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc index e9a1090934d..804d1c52449 100644 --- a/chromium/cc/animation/keyframe_effect.cc +++ b/chromium/cc/animation/keyframe_effect.cc @@ -67,10 +67,15 @@ KeyframeEffect::~KeyframeEffect() { void KeyframeEffect::SetNeedsPushProperties() { needs_push_properties_ = true; + // The keyframe effect may have been removed from the main thread while + // an event was in flight from the compositor. In this case, we may need + // to push the removal to the compositor but do not expect to have a bound + // element animations instance. // TODO(smcgruer): We only need the below calls when needs_push_properties_ // goes from false to true - see http://crbug.com/764405 - DCHECK(element_animations()); - element_animations_->SetNeedsPushProperties(); + if (element_animations()) { + element_animations_->SetNeedsPushProperties(); + } animation_->SetNeedsPushProperties(); } @@ -443,7 +448,8 @@ bool KeyframeEffect::AnimationsPreserveAxisAlignment() const { return true; } -float KeyframeEffect::MaximumScale(ElementListType list_type) const { +float KeyframeEffect::MaximumScale(ElementId element_id, + ElementListType list_type) const { float maximum_scale = kInvalidScale; for (const auto& keyframe_model : keyframe_models()) { if (keyframe_model->is_finished()) @@ -452,6 +458,12 @@ float KeyframeEffect::MaximumScale(ElementListType list_type) const { auto* cc_keyframe_model = KeyframeModel::ToCcKeyframeModel(keyframe_model.get()); + ElementId model_element_id = cc_keyframe_model->element_id(); + if (!model_element_id) + model_element_id = element_id_; + if (model_element_id != element_id) + continue; + if ((list_type == ElementListType::ACTIVE && !cc_keyframe_model->affects_active_elements()) || (list_type == ElementListType::PENDING && diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h index 45cb8cf3eb5..1ce30ccd2a0 100644 --- a/chromium/cc/animation/keyframe_effect.h +++ b/chromium/cc/animation/keyframe_effect.h @@ -120,7 +120,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect : public gfx::KeyframeEffect { // Returns the maximum scale along any dimension at any destination in active // scale animations, or kInvalidScale if there is no active transform // animation or the scale cannot be computed. - float MaximumScale(ElementListType) const; + float MaximumScale(ElementId, ElementListType) 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 diff --git a/chromium/cc/animation/keyframe_model_unittest.cc b/chromium/cc/animation/keyframe_model_unittest.cc index 8d95bcda0d0..32edc756ed2 100644 --- a/chromium/cc/animation/keyframe_model_unittest.cc +++ b/chromium/cc/animation/keyframe_model_unittest.cc @@ -1385,7 +1385,7 @@ TEST(KeyframeModelTest, ToString) { std::make_unique<FakeFloatAnimationCurve>(15), 42, 73, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)); EXPECT_EQ(base::StringPrintf( - "KeyframeModel{id=%d, group=73, target_property_type=1, " + "KeyframeModel{id=%d, group=73, target_property_type=4, " "custom_property_name=, native_property_type=2, " "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}", keyframe_model->id()), diff --git a/chromium/cc/base/list_container_helper.cc b/chromium/cc/base/list_container_helper.cc index 319f0d6c0b7..70e5c1af765 100644 --- a/chromium/cc/base/list_container_helper.cc +++ b/chromium/cc/base/list_container_helper.cc @@ -13,6 +13,7 @@ #include "base/check_op.h" #include "base/memory/aligned_memory.h" +#include "base/memory/raw_ptr_exclusion.h" namespace { const size_t kDefaultNumElementTypesToReserve = 32; @@ -265,7 +266,7 @@ class ListContainerHelper::CharAllocator { // // `last_list_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - InnerList* last_list_; + RAW_PTR_EXCLUSION InnerList* last_list_; }; // PositionInCharAllocator diff --git a/chromium/cc/base/list_container_helper.h b/chromium/cc/base/list_container_helper.h index 1b34ca790ae..8df56ebd7ee 100644 --- a/chromium/cc/base/list_container_helper.h +++ b/chromium/cc/base/list_container_helper.h @@ -9,6 +9,7 @@ #include <memory> +#include "base/memory/raw_ptr_exclusion.h" #include "cc/base/base_export.h" namespace cc { @@ -38,13 +39,13 @@ class CC_BASE_EXPORT ListContainerHelper final { struct CC_BASE_EXPORT PositionInCharAllocator { // `ptr_to_container` is not a raw_ptr<...> for performance reasons (based // on analysis of sampling profiler data and tab_search:top100:2020). - CharAllocator* ptr_to_container; + RAW_PTR_EXCLUSION CharAllocator* ptr_to_container; size_t vector_index; // `item_iterator` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - char* item_iterator; + RAW_PTR_EXCLUSION char* item_iterator; PositionInCharAllocator(const PositionInCharAllocator& other); PositionInCharAllocator& operator=(const PositionInCharAllocator& other); diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc index 1aed6c19f96..7c700f83238 100644 --- a/chromium/cc/base/math_util.cc +++ b/chromium/cc/base/math_util.cc @@ -1007,6 +1007,7 @@ void MathUtil::AddCornerRadiiToTracedValue( res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).y()); res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x()); res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).y()); + res->EndArray(); } void MathUtil::AddToTracedValue(const char* name, diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h index a29fc4986a3..02aaebdc01f 100644 --- a/chromium/cc/base/math_util.h +++ b/chromium/cc/base/math_util.h @@ -5,22 +5,18 @@ #ifndef CC_BASE_MATH_UTIL_H_ #define CC_BASE_MATH_UTIL_H_ +#include <cmath> #include <limits> -#include <memory> -#include <vector> #include "base/check.h" #include "base/cxx17_backports.h" #include "build/build_config.h" #include "cc/base/base_export.h" #include "third_party/skia/include/core/SkM44.h" +#include "third_party/skia/include/core/SkScalar.h" #include "ui/gfx/geometry/box_f.h" #include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/point_f.h" -#include "ui/gfx/geometry/rounded_corners_f.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/geometry/transform.h" -#include "ui/gfx/geometry/vector2d_f.h" namespace base { class Value; @@ -34,6 +30,7 @@ class QuadF; class Rect; class RectF; class RRectF; +class Size; class SizeF; class Transform; class Vector2dF; diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h index 35f5ebcdf0a..d59c08a7f22 100644 --- a/chromium/cc/base/rtree.h +++ b/chromium/cc/base/rtree.h @@ -94,8 +94,8 @@ class RTree { private: // These values were empirically determined to produce reasonable performance // in most cases. - enum { kMinChildren = 6 }; - enum { kMaxChildren = 11 }; + static constexpr int kMinChildren = 6; + static constexpr int kMaxChildren = 11; template <typename U> struct Node; diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc index 81644efb821..db96fd4c515 100644 --- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc +++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc @@ -48,7 +48,7 @@ void RunBenchmark(RasterSource* raster_source, // quantization when the layer is very small. base::LapTimer timer(kWarmupRuns, base::Milliseconds(kTimeLimitMillis), kTimeCheckInterval); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( content_rect, 1.f / contents_scale.x(), 1.f / contents_scale.y()); *is_solid_color = diff --git a/chromium/cc/cc.gni b/chromium/cc/cc.gni index 651cc7f0f2c..d731f680dbc 100644 --- a/chromium/cc/cc.gni +++ b/chromium/cc/cc.gni @@ -23,9 +23,6 @@ template("cc_component") { } configs -= cc_remove_configs configs += cc_add_configs - - # TODO(crbug.com/1292951): Remove this line. - configs -= [ "//build/config/compiler:prevent_unsafe_narrowing" ] } } @@ -40,9 +37,6 @@ template("cc_test_static_library") { # Not needed in test code. configs -= [ "//build/config/compiler:wexit_time_destructors" ] - - # TODO(crbug.com/1292951): Remove this line. - configs -= [ "//build/config/compiler:prevent_unsafe_narrowing" ] } } @@ -57,8 +51,5 @@ template("cc_test") { # Not needed in test code. configs -= [ "//build/config/compiler:wexit_time_destructors" ] - - # TODO(crbug.com/1292951): Remove this line. - configs -= [ "//build/config/compiler:prevent_unsafe_narrowing" ] } } diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc index a90c7d34c38..6b91453f0e6 100644 --- a/chromium/cc/debug/debug_colors.cc +++ b/chromium/cc/debug/debug_colors.cc @@ -16,48 +16,48 @@ static float Scale(float width, float device_scale_factor) { // ======= Layer border colors ======= // Tiled content layers are orange. -SkColor DebugColors::TiledContentLayerBorderColor() { - return SkColorSetARGB(128, 255, 128, 0); +SkColor4f DebugColors::TiledContentLayerBorderColor() { + return {1.0f, 0.5f, 0.0f, 0.5f}; } int DebugColors::TiledContentLayerBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Image layers are olive. -SkColor DebugColors::ImageLayerBorderColor() { - return SkColorSetARGB(128, 128, 128, 0); +SkColor4f DebugColors::ImageLayerBorderColor() { + return {0.5f, 0.5f, 0.0f, 0.5f}; } int DebugColors::ImageLayerBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Non-tiled content layers area green. -SkColor DebugColors::ContentLayerBorderColor() { - return SkColorSetARGB(128, 0, 128, 32); +SkColor4f DebugColors::ContentLayerBorderColor() { + return {0.0f, 0.5f, 32.0f / 255.0f, 0.5f}; } int DebugColors::ContentLayerBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Other container layers are yellow. -SkColor DebugColors::ContainerLayerBorderColor() { - return SkColorSetARGB(192, 255, 255, 0); +SkColor4f DebugColors::ContainerLayerBorderColor() { + return {1.0f, 1.0f, 0.0f, 0.75f}; } int DebugColors::ContainerLayerBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Surface layers are a blue-ish green. -SkColor DebugColors::SurfaceLayerBorderColor() { - return SkColorSetARGB(128, 0, 255, 136); +SkColor4f DebugColors::SurfaceLayerBorderColor() { + return {0.0f, 1.0f, 136.0f / 255.0f, 0.5f}; } int DebugColors::SurfaceLayerBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Render surfaces are blue. -SkColor DebugColors::SurfaceBorderColor() { - return SkColorSetARGB(100, 0, 0, 255); +SkColor4f DebugColors::SurfaceBorderColor() { + return {0.0f, 0.0f, 1.0f, 100.0f / 255.0f}; } int DebugColors::SurfaceBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); @@ -66,64 +66,64 @@ int DebugColors::SurfaceBorderWidth(float device_scale_factor) { // ======= Tile colors ======= // High-res tile borders are cyan. -SkColor DebugColors::HighResTileBorderColor() { - return SkColorSetARGB(100, 80, 200, 200); +SkColor4f DebugColors::HighResTileBorderColor() { + return {80.0f / 255.0f, 200.0f / 255.0f, 200.0f / 255.0f, 100.0f / 255.0f}; } int DebugColors::HighResTileBorderWidth(float device_scale_factor) { return Scale(1, device_scale_factor); } // Low-res tile borders are purple. -SkColor DebugColors::LowResTileBorderColor() { - return SkColorSetARGB(100, 212, 83, 192); +SkColor4f DebugColors::LowResTileBorderColor() { + return {212.0f / 255.0f, 83.0f / 255.0f, 0.75f, 100.0f / 255.0f}; } int DebugColors::LowResTileBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Other high-resolution tile borders are yellow. -SkColor DebugColors::ExtraHighResTileBorderColor() { - return SkColorSetARGB(100, 239, 231, 20); +SkColor4f DebugColors::ExtraHighResTileBorderColor() { + return {239.0f / 255.0f, 231.0f / 255.0f, 20.0f / 255.0f, 100.0f / 255.0f}; } int DebugColors::ExtraHighResTileBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Other low-resolution tile borders are green. -SkColor DebugColors::ExtraLowResTileBorderColor() { - return SkColorSetARGB(100, 93, 186, 18); +SkColor4f DebugColors::ExtraLowResTileBorderColor() { + return {93.0f / 255.0f, 186.0f / 255.0f, 18.0f / 255.0f, 100.0f / 255.0f}; } int DebugColors::ExtraLowResTileBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); } // Missing tile borders are dark grey. -SkColor DebugColors::MissingTileBorderColor() { - return SkColorSetARGB(64, 64, 64, 0); +SkColor4f DebugColors::MissingTileBorderColor() { + return {0.25f, 0.25f, 0.0f, 0.25f}; } int DebugColors::MissingTileBorderWidth(float device_scale_factor) { return Scale(1, device_scale_factor); } // Solid color tile borders are grey. -SkColor DebugColors::SolidColorTileBorderColor() { - return SkColorSetARGB(128, 128, 128, 128); +SkColor4f DebugColors::SolidColorTileBorderColor() { + return {0.5f, 0.5f, 0.5f, 0.5f}; } int DebugColors::SolidColorTileBorderWidth(float device_scale_factor) { return Scale(1, device_scale_factor); } // OOM tile borders are red. -SkColor DebugColors::OOMTileBorderColor() { - return SkColorSetARGB(100, 255, 0, 0); +SkColor4f DebugColors::OOMTileBorderColor() { + return {1.0f, 0.0f, 0.0f, 100.0f / 255.0f}; } int DebugColors::OOMTileBorderWidth(float device_scale_factor) { return Scale(1, device_scale_factor); } // Direct picture borders are chartreuse. -SkColor DebugColors::DirectPictureBorderColor() { - return SkColorSetARGB(255, 127, 255, 0); +SkColor4f DebugColors::DirectPictureBorderColor() { + return {127.0f / 255.0f, 1.0f, 0.0f, 1.0f}; } int DebugColors::DirectPictureBorderWidth(float device_scale_factor) { return Scale(1, device_scale_factor); @@ -146,8 +146,8 @@ DebugColors::TintCompositedContentColorTransformMatrix() { } // Compressed tile borders are blue. -SkColor DebugColors::CompressedTileBorderColor() { - return SkColorSetARGB(100, 20, 20, 240); +SkColor4f DebugColors::CompressedTileBorderColor() { + return {20.0f / 255.0f, 20.0f / 255.0f, 240.0f / 255.0f, 100.0f / 255.0f}; } int DebugColors::CompressedTileBorderWidth(float device_scale_factor) { return Scale(2, device_scale_factor); @@ -156,211 +156,214 @@ int DebugColors::CompressedTileBorderWidth(float device_scale_factor) { // ======= Checkerboard colors ======= // Non-debug checkerboards are grey. -SkColor DebugColors::DefaultCheckerboardColor() { - return SkColorSetRGB(241, 241, 241); +SkColor4f DebugColors::DefaultCheckerboardColor() { + return {241.0f / 255.0f, 241.0f / 255.0f, 241.0f / 255.0f, 1.0f}; } // Invalidated tiles get sky blue checkerboards. -SkColor DebugColors::InvalidatedTileCheckerboardColor() { - return SkColorSetRGB(128, 200, 245); +SkColor4f DebugColors::InvalidatedTileCheckerboardColor() { + return {0.5f, 200.0f / 255.0f, 245.0f / 255.0f, 1.0f}; } // Evicted tiles get pale red checkerboards. -SkColor DebugColors::EvictedTileCheckerboardColor() { - return SkColorSetRGB(255, 200, 200); +SkColor4f DebugColors::EvictedTileCheckerboardColor() { + return {1.0f, 200.0f / 255.0f, 200.0f / 255.0f, 1.0f}; } // ======= Debug rect colors ======= -static SkColor FadedGreen(int initial_value, int step) { +static SkColor4f FadedGreen(int initial_value, int step) { DCHECK_GE(step, 0); DCHECK_LE(step, DebugColors::kFadeSteps); int value = step * initial_value / DebugColors::kFadeSteps; - return SkColorSetARGB(value, 0, 195, 0); + return {0.0f, 195.0f / 255.0f, 0.0f, static_cast<float>(value) / 255.0f}; } // Paint rects in green. -SkColor DebugColors::PaintRectBorderColor(int step) { +SkColor4f DebugColors::PaintRectBorderColor(int step) { return FadedGreen(255, step); } int DebugColors::PaintRectBorderWidth() { return 2; } -SkColor DebugColors::PaintRectFillColor(int step) { +SkColor4f DebugColors::PaintRectFillColor(int step) { return FadedGreen(60, step); } -static SkColor FadedBlue(int initial_value, int step) { +static SkColor4f FadedBlue(int initial_value, int step) { DCHECK_GE(step, 0); DCHECK_LE(step, DebugColors::kFadeSteps); int value = step * initial_value / DebugColors::kFadeSteps; - return SkColorSetARGB(value, 0, 0, 255); + return {0.0f, 0.0f, 1.0f, static_cast<float>(value) / 255.0f}; } /// Layout Shift rects in blue. -SkColor DebugColors::LayoutShiftRectBorderColor() { - return SkColorSetARGB(0, 0, 0, 255); +SkColor4f DebugColors::LayoutShiftRectBorderColor() { + return {0.0f, 0.0f, 1.0f, 0.0f}; } int DebugColors::LayoutShiftRectBorderWidth() { // We don't want any border showing for the layout shift debug rects so we set // the border width to be equal to 0. return 0; } -SkColor DebugColors::LayoutShiftRectFillColor(int step) { +SkColor4f DebugColors::LayoutShiftRectFillColor(int step) { return FadedBlue(60, step); } // Property-changed rects in blue. -SkColor DebugColors::PropertyChangedRectBorderColor() { - return SkColorSetARGB(255, 0, 0, 255); +SkColor4f DebugColors::PropertyChangedRectBorderColor() { + return {0.0f, 0.0f, 1.0f, 1.0f}; } int DebugColors::PropertyChangedRectBorderWidth() { return 2; } -SkColor DebugColors::PropertyChangedRectFillColor() { - return SkColorSetARGB(30, 0, 0, 255); +SkColor4f DebugColors::PropertyChangedRectFillColor() { + return {0.0f, 0.0f, 1.0f, 30.0f / 255.0f}; } // Surface damage rects in yellow-orange. -SkColor DebugColors::SurfaceDamageRectBorderColor() { - return SkColorSetARGB(255, 200, 100, 0); +SkColor4f DebugColors::SurfaceDamageRectBorderColor() { + return {200.0f / 255.0f, 100.0f / 255.0f, 0.0f, 1.0f}; } int DebugColors::SurfaceDamageRectBorderWidth() { return 2; } -SkColor DebugColors::SurfaceDamageRectFillColor() { - return SkColorSetARGB(30, 200, 100, 0); +SkColor4f DebugColors::SurfaceDamageRectFillColor() { + return {200.0f / 255.0f, 100.0f / 255.0f, 0.0f, 30.0f / 255.0f}; } // Surface screen space rects in yellow-green. -SkColor DebugColors::ScreenSpaceLayerRectBorderColor() { - return SkColorSetARGB(255, 100, 200, 0); +SkColor4f DebugColors::ScreenSpaceLayerRectBorderColor() { + return {100.0f / 255.0f, 200.0f / 255.0f, 0.0f, 1.0f}; } int DebugColors::ScreenSpaceLayerRectBorderWidth() { return 2; } -SkColor DebugColors::ScreenSpaceLayerRectFillColor() { - return SkColorSetARGB(30, 100, 200, 0); +SkColor4f DebugColors::ScreenSpaceLayerRectFillColor() { + return {100.0f / 255.0f, 200.0f / 255.0f, 0.0f, 30.0f / 255.0f}; } // Touch-event-handler rects in yellow. -SkColor DebugColors::TouchEventHandlerRectBorderColor() { - return SkColorSetARGB(255, 239, 229, 60); +SkColor4f DebugColors::TouchEventHandlerRectBorderColor() { + return {239.0f / 255.0f, 229.0f / 255.0f, 60.0f / 255.0f, 1.0f}; } int DebugColors::TouchEventHandlerRectBorderWidth() { return 2; } -SkColor DebugColors::TouchEventHandlerRectFillColor() { - return SkColorSetARGB(30, 239, 229, 60); +SkColor4f DebugColors::TouchEventHandlerRectFillColor() { + return {239.0f / 255.0f, 229.0f / 255.0f, 60.0f / 255.0f, 30.0f / 255.0f}; } // Wheel-event-handler rects in green. -SkColor DebugColors::WheelEventHandlerRectBorderColor() { - return SkColorSetARGB(255, 189, 209, 57); +SkColor4f DebugColors::WheelEventHandlerRectBorderColor() { + return {189.0f / 255.0f, 209.0f / 255.0f, 57.0f / 255.0f, 1.0f}; } int DebugColors::WheelEventHandlerRectBorderWidth() { return 2; } -SkColor DebugColors::WheelEventHandlerRectFillColor() { - return SkColorSetARGB(30, 189, 209, 57); +SkColor4f DebugColors::WheelEventHandlerRectFillColor() { + return {189.0f / 255.0f, 209.0f / 255.0f, 57.0f / 255.0f, 30.0f / 255.0f}; } // Scroll-event-handler rects in teal. -SkColor DebugColors::ScrollEventHandlerRectBorderColor() { - return SkColorSetARGB(255, 24, 167, 181); +SkColor4f DebugColors::ScrollEventHandlerRectBorderColor() { + return {24.0f / 255.0f, 167.0f / 255.0f, 181.0f / 255.0f, 1.0f}; } int DebugColors::ScrollEventHandlerRectBorderWidth() { return 2; } -SkColor DebugColors::ScrollEventHandlerRectFillColor() { - return SkColorSetARGB(30, 24, 167, 181); +SkColor4f DebugColors::ScrollEventHandlerRectFillColor() { + return {24.0f / 255.0f, 167.0f / 255.0f, 181.0f / 255.0f, 30.0f / 255.0f}; } // Non-fast-scrollable rects in orange. -SkColor DebugColors::NonFastScrollableRectBorderColor() { - return SkColorSetARGB(255, 238, 163, 59); +SkColor4f DebugColors::NonFastScrollableRectBorderColor() { + return {238.0f / 255.0f, 163.0f / 255.0f, 59.0f / 255.0f, 1.0f}; } int DebugColors::NonFastScrollableRectBorderWidth() { return 2; } -SkColor DebugColors::NonFastScrollableRectFillColor() { - return SkColorSetARGB(30, 238, 163, 59); +SkColor4f DebugColors::NonFastScrollableRectFillColor() { + return {238.0f / 255.0f, 163.0f / 255.0f, 59.0f / 255.0f, 30.0f / 255.0f}; } // Main-thread scrolling reason rects in yellow-orange. -SkColor DebugColors::MainThreadScrollingReasonRectBorderColor() { - return SkColorSetARGB(255, 200, 100, 0); +SkColor4f DebugColors::MainThreadScrollingReasonRectBorderColor() { + return {200.0f / 255.0f, 100.0f / 255.0f, 0.0f, 1.0f}; } int DebugColors::MainThreadScrollingReasonRectBorderWidth() { return 2; } -SkColor DebugColors::MainThreadScrollingReasonRectFillColor() { - return SkColorSetARGB(30, 200, 100, 0); +SkColor4f DebugColors::MainThreadScrollingReasonRectFillColor() { + return {200.0f / 255.0f, 100.0f / 255.0f, 0.0f, 30.0f / 255.0f}; } // Animation bounds are lime-green. -SkColor DebugColors::LayerAnimationBoundsBorderColor() { - return SkColorSetARGB(255, 112, 229, 0); +SkColor4f DebugColors::LayerAnimationBoundsBorderColor() { + return {112.0f / 255.0f, 229.0f / 255.0f, 0.0f, 1.0f}; } int DebugColors::LayerAnimationBoundsBorderWidth() { return 2; } -SkColor DebugColors::LayerAnimationBoundsFillColor() { - return SkColorSetARGB(30, 112, 229, 0); +SkColor4f DebugColors::LayerAnimationBoundsFillColor() { + return {112.0f / 255.0f, 229.0f / 255.0f, 0.0f, 30.0f / 255.0f}; } // Picture borders in transparent blue. -SkColor DebugColors::PictureBorderColor() { - return SkColorSetARGB(100, 0, 0, 200); +SkColor4f DebugColors::PictureBorderColor() { + return {0.0f, 0.0f, 200.0f / 255.0f, 100.0f / 255.0f}; } // ======= HUD widget colors ======= -SkColor DebugColors::HUDBackgroundColor() { - return SkColorSetARGB(217, 0, 0, 0); +SkColor4f DebugColors::HUDBackgroundColor() { + return {0.0f, 0.0f, 0.0f, 217.0f / 255.0f}; } -SkColor DebugColors::HUDSeparatorLineColor() { - return SkColorSetARGB(64, 0, 255, 0); +SkColor4f DebugColors::HUDSeparatorLineColor() { + return {0.0f, 1.0f, 0.0f, 0.25f}; } -SkColor DebugColors::HUDIndicatorLineColor() { - return SK_ColorYELLOW; +SkColor4f DebugColors::HUDIndicatorLineColor() { + return SkColors::kYellow; } -SkColor DebugColors::HUDTitleColor() { - return SkColorSetARGB(255, 232, 232, 232); +SkColor4f DebugColors::HUDTitleColor() { + return {232.0f / 255.0f, 232.0f / 255.0f, 232.0f / 255.0f, 1.0f}; } -SkColor DebugColors::PlatformLayerTreeTextColor() { return SK_ColorRED; } -SkColor DebugColors::FPSDisplayTextAndGraphColor() { - return SK_ColorGREEN; +SkColor4f DebugColors::PlatformLayerTreeTextColor() { + return SkColors::kRed; +} +SkColor4f DebugColors::FPSDisplayTextAndGraphColor() { + return SkColors::kGreen; } // Color used to represent dropped compositor frames. -SkColor DebugColors::FPSDisplayDroppedFrame() { - return SkColorSetRGB(202, 91, 29); +SkColor4f DebugColors::FPSDisplayDroppedFrame() { + return {202.0f / 255.0f, 91.0f / 255.0f, 29.0f / 255.0f, 1.0f}; } // Color used to represent a "partial" frame, i.e. a frame that missed // its commit deadline. -SkColor DebugColors::FPSDisplayMissedFrame() { - return SkColorSetRGB(255, 245, 0); +SkColor4f DebugColors::FPSDisplayMissedFrame() { + return {1.0f, 245.0f / 255.0f, 0.0f, 1.0f}; } // Color used to represent a frame that successfully rendered. -SkColor DebugColors::FPSDisplaySuccessfulFrame() { - return SkColorSetARGB(191, 174, 221, 255); +SkColor4f DebugColors::FPSDisplaySuccessfulFrame() { + return {174.0f / 255.0f, 221.0f / 255.0f, 1.0f, 191.0f / 255.0f}; } -SkColor DebugColors::MemoryDisplayTextColor() { - return SK_ColorCYAN; +SkColor4f DebugColors::MemoryDisplayTextColor() { + return SkColors::kCyan; } // Paint time display in green (similar to paint times in the WebInspector) -SkColor DebugColors::PaintTimeDisplayTextAndGraphColor() { - return SkColorSetRGB(75, 155, 55); +SkColor4f DebugColors::PaintTimeDisplayTextAndGraphColor() { + return {75.0f / 255.0f, 155.0f / 255.0f, 55.0f / 255.0f, 1.0f}; } -SkColor DebugColors::NonLCDTextHighlightColor(LCDTextDisallowedReason reason) { +SkColor4f DebugColors::NonLCDTextHighlightColor( + LCDTextDisallowedReason reason) { switch (reason) { case LCDTextDisallowedReason::kNone: case LCDTextDisallowedReason::kNoText: - return SK_ColorTRANSPARENT; + return SkColors::kTransparent; case LCDTextDisallowedReason::kSetting: - return SkColorSetARGB(96, 128, 255, 0); + return {0.5f, 1.0f, 0.0f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kBackgroundColorNotOpaque: - return SkColorSetARGB(96, 128, 128, 0); + return {0.5f, 0.5f, 0.0f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kContentsNotOpaque: - return SkColorSetARGB(96, 255, 0, 0); + return {1.0f, 0.0f, 0.0f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kNonIntegralTranslation: - return SkColorSetARGB(96, 255, 128, 0); + return {1.0f, 0.5f, 0.0f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kNonIntegralXOffset: case LCDTextDisallowedReason::kNonIntegralYOffset: - return SkColorSetARGB(96, 255, 0, 128); + return {1.0f, 0.0f, 0.5f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kWillChangeTransform: case LCDTextDisallowedReason::kTransformAnimation: - return SkColorSetARGB(96, 128, 0, 255); + return {0.5f, 0.0f, 1.0f, 96.0f / 255.0f}; case LCDTextDisallowedReason::kPixelOrColorEffect: - return SkColorSetARGB(96, 0, 128, 0); + return {0.0f, 0.5f, 0.0f, 96.0f / 255.0f}; } NOTREACHED(); - return SK_ColorTRANSPARENT; + return SkColors::kTransparent; } } // namespace cc diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h index 109bb13b2ef..49ad7f389eb 100644 --- a/chromium/cc/debug/debug_colors.h +++ b/chromium/cc/debug/debug_colors.h @@ -16,121 +16,121 @@ class CC_DEBUG_EXPORT DebugColors { public: DebugColors() = delete; - static SkColor TiledContentLayerBorderColor(); + static SkColor4f TiledContentLayerBorderColor(); static int TiledContentLayerBorderWidth(float device_scale_factor); - static SkColor ImageLayerBorderColor(); + static SkColor4f ImageLayerBorderColor(); static int ImageLayerBorderWidth(float device_scale_factor); - static SkColor ContentLayerBorderColor(); + static SkColor4f ContentLayerBorderColor(); static int ContentLayerBorderWidth(float device_scale_factor); - static SkColor ContainerLayerBorderColor(); + static SkColor4f ContainerLayerBorderColor(); static int ContainerLayerBorderWidth(float device_scale_factor); - static SkColor SurfaceLayerBorderColor(); + static SkColor4f SurfaceLayerBorderColor(); static int SurfaceLayerBorderWidth(float device_scale_factor); - static SkColor SurfaceBorderColor(); + static SkColor4f SurfaceBorderColor(); static int SurfaceBorderWidth(float device_scale_factor); - static SkColor HighResTileBorderColor(); + static SkColor4f HighResTileBorderColor(); static int HighResTileBorderWidth(float device_scale_factor); - static SkColor LowResTileBorderColor(); + static SkColor4f LowResTileBorderColor(); static int LowResTileBorderWidth(float device_scale_factor); - static SkColor ExtraHighResTileBorderColor(); + static SkColor4f ExtraHighResTileBorderColor(); static int ExtraHighResTileBorderWidth(float device_scale_factor); - static SkColor ExtraLowResTileBorderColor(); + static SkColor4f ExtraLowResTileBorderColor(); static int ExtraLowResTileBorderWidth(float device_scale_factor); - static SkColor MissingTileBorderColor(); + static SkColor4f MissingTileBorderColor(); static int MissingTileBorderWidth(float device_scale_factor); - static SkColor SolidColorTileBorderColor(); + static SkColor4f SolidColorTileBorderColor(); static int SolidColorTileBorderWidth(float device_scale_factor); - static SkColor OOMTileBorderColor(); + static SkColor4f OOMTileBorderColor(); static int OOMTileBorderWidth(float device_scale_factor); - static SkColor DirectPictureBorderColor(); + static SkColor4f DirectPictureBorderColor(); static int DirectPictureBorderWidth(float device_scale_factor); - static SkColor CompressedTileBorderColor(); + static SkColor4f CompressedTileBorderColor(); static int CompressedTileBorderWidth(float device_scale_factor); - static SkColor DefaultCheckerboardColor(); - static SkColor EvictedTileCheckerboardColor(); - static SkColor InvalidatedTileCheckerboardColor(); + static SkColor4f DefaultCheckerboardColor(); + static SkColor4f EvictedTileCheckerboardColor(); + static SkColor4f InvalidatedTileCheckerboardColor(); static const int kFadeSteps = 50; - static SkColor PaintRectBorderColor(int step); + static SkColor4f PaintRectBorderColor(int step); static int PaintRectBorderWidth(); - static SkColor PaintRectFillColor(int step); + static SkColor4f PaintRectFillColor(int step); - static SkColor LayoutShiftRectBorderColor(); + static SkColor4f LayoutShiftRectBorderColor(); static int LayoutShiftRectBorderWidth(); - static SkColor LayoutShiftRectFillColor(int step); + static SkColor4f LayoutShiftRectFillColor(int step); - static SkColor PropertyChangedRectBorderColor(); + static SkColor4f PropertyChangedRectBorderColor(); static int PropertyChangedRectBorderWidth(); - static SkColor PropertyChangedRectFillColor(); + static SkColor4f PropertyChangedRectFillColor(); - static SkColor SurfaceDamageRectBorderColor(); + static SkColor4f SurfaceDamageRectBorderColor(); static int SurfaceDamageRectBorderWidth(); - static SkColor SurfaceDamageRectFillColor(); + static SkColor4f SurfaceDamageRectFillColor(); - static SkColor ScreenSpaceLayerRectBorderColor(); + static SkColor4f ScreenSpaceLayerRectBorderColor(); static int ScreenSpaceLayerRectBorderWidth(); - static SkColor ScreenSpaceLayerRectFillColor(); + static SkColor4f ScreenSpaceLayerRectFillColor(); - static SkColor TouchEventHandlerRectBorderColor(); + static SkColor4f TouchEventHandlerRectBorderColor(); static int TouchEventHandlerRectBorderWidth(); - static SkColor TouchEventHandlerRectFillColor(); + static SkColor4f TouchEventHandlerRectFillColor(); - static SkColor WheelEventHandlerRectBorderColor(); + static SkColor4f WheelEventHandlerRectBorderColor(); static int WheelEventHandlerRectBorderWidth(); - static SkColor WheelEventHandlerRectFillColor(); + static SkColor4f WheelEventHandlerRectFillColor(); - static SkColor ScrollEventHandlerRectBorderColor(); + static SkColor4f ScrollEventHandlerRectBorderColor(); static int ScrollEventHandlerRectBorderWidth(); - static SkColor ScrollEventHandlerRectFillColor(); + static SkColor4f ScrollEventHandlerRectFillColor(); - static SkColor NonFastScrollableRectBorderColor(); + static SkColor4f NonFastScrollableRectBorderColor(); static int NonFastScrollableRectBorderWidth(); - static SkColor NonFastScrollableRectFillColor(); + static SkColor4f NonFastScrollableRectFillColor(); - static SkColor MainThreadScrollingReasonRectBorderColor(); + static SkColor4f MainThreadScrollingReasonRectBorderColor(); static int MainThreadScrollingReasonRectBorderWidth(); - static SkColor MainThreadScrollingReasonRectFillColor(); + static SkColor4f MainThreadScrollingReasonRectFillColor(); - static SkColor LayerAnimationBoundsBorderColor(); + static SkColor4f LayerAnimationBoundsBorderColor(); static int LayerAnimationBoundsBorderWidth(); - static SkColor LayerAnimationBoundsFillColor(); + static SkColor4f LayerAnimationBoundsFillColor(); - static SkColor NonPaintedFillColor(); - static SkColor MissingPictureFillColor(); - static SkColor MissingResizeInvalidations(); - static SkColor PictureBorderColor(); + static SkColor4f NonPaintedFillColor(); + static SkColor4f MissingPictureFillColor(); + static SkColor4f MissingResizeInvalidations(); + static SkColor4f PictureBorderColor(); static base::span<const float> TintCompositedContentColorTransformMatrix(); - static SkColor HUDBackgroundColor(); - static SkColor HUDSeparatorLineColor(); - static SkColor HUDIndicatorLineColor(); - static SkColor HUDTitleColor(); + static SkColor4f HUDBackgroundColor(); + static SkColor4f HUDSeparatorLineColor(); + static SkColor4f HUDIndicatorLineColor(); + static SkColor4f HUDTitleColor(); - static SkColor PlatformLayerTreeTextColor(); - static SkColor FPSDisplayTextAndGraphColor(); - static SkColor FPSDisplayDroppedFrame(); - static SkColor FPSDisplayMissedFrame(); - static SkColor FPSDisplaySuccessfulFrame(); - static SkColor MemoryDisplayTextColor(); - static SkColor PaintTimeDisplayTextAndGraphColor(); + static SkColor4f PlatformLayerTreeTextColor(); + static SkColor4f FPSDisplayTextAndGraphColor(); + static SkColor4f FPSDisplayDroppedFrame(); + static SkColor4f FPSDisplayMissedFrame(); + static SkColor4f FPSDisplaySuccessfulFrame(); + static SkColor4f MemoryDisplayTextColor(); + static SkColor4f PaintTimeDisplayTextAndGraphColor(); - static SkColor NonLCDTextHighlightColor(LCDTextDisallowedReason); + static SkColor4f NonLCDTextHighlightColor(LCDTextDisallowedReason); }; } // namespace cc diff --git a/chromium/cc/input/compositor_input_interfaces.h b/chromium/cc/input/compositor_input_interfaces.h index dcbd420b2cc..cdc8b4f10d4 100644 --- a/chromium/cc/input/compositor_input_interfaces.h +++ b/chromium/cc/input/compositor_input_interfaces.h @@ -57,6 +57,10 @@ class InputDelegateForCompositor { virtual void RootLayerStateMayHaveChanged() = 0; // Called to let the input handler know that a scrollbar for the given + // elementId has been added. + virtual void DidRegisterScrollbar(ElementId scroll_element_id, + ScrollbarOrientation orientation) = 0; + // Called to let the input handler know that a scrollbar for the given // elementId has been removed. virtual void DidUnregisterScrollbar(ElementId scroll_element_id, ScrollbarOrientation orientation) = 0; @@ -98,6 +102,7 @@ class CompositorDelegateForInput { virtual bool HasAnimatedScrollbars() const = 0; virtual void SetNeedsCommit() = 0; virtual void SetNeedsFullViewportRedraw() = 0; + virtual void SetDeferBeginMainFrame(bool defer_begin_main_frame) const = 0; virtual void DidUpdateScrollAnimationCurve() = 0; virtual void AccumulateScrollDeltaForTracing(const gfx::Vector2dF& delta) = 0; virtual void DidStartPinchZoom() = 0; diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h index a242013bb07..ae2ff545aa7 100644 --- a/chromium/cc/input/input_handler.h +++ b/chromium/cc/input/input_handler.h @@ -94,6 +94,12 @@ struct CC_EXPORT InputHandlerScrollResult { // scrolling node is the viewport, this would be the sum of the scroll offsets // of the inner and outer node, representing the visual scroll offset. gfx::PointF current_visual_offset; + // Used only in scroll unification. Tells the caller that we have performed + // the scroll (i.e. updated the offset in the scroll tree) on the compositor + // thread, but we will need a main thread lifecycle update + commit before + // the user will see the new pixels (for example, because the scroller does + // not have a composited layer). + bool needs_main_thread_repaint = false; }; class CC_EXPORT InputHandlerClient { @@ -394,6 +400,11 @@ class CC_EXPORT InputHandler { // Returns true if ScrollbarController is in the middle of a scroll operation. virtual bool ScrollbarScrollIsActive() = 0; + // Defers posting BeginMainFrame tasks. This is used during the main thread + // hit test for a GestureScrollBegin, to avoid posting a frame before the + // compositor thread has had a chance to update the scroll offset. + virtual void SetDeferBeginMainFrame(bool defer_begin_main_frame) const = 0; + protected: virtual ~InputHandler() = default; InputHandler() = default; diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc index 098d0419e4e..a3eba61f9f8 100644 --- a/chromium/cc/input/scrollbar_animation_controller.cc +++ b/chromium/cc/input/scrollbar_animation_controller.cc @@ -55,6 +55,7 @@ ScrollbarAnimationController::ScrollbarAnimationController( opacity_(initial_opacity), show_scrollbars_on_scroll_gesture_(false), need_thinning_animation_(false), + need_fade_animation_(true), is_mouse_down_(false), tickmarks_showing_(false) {} @@ -75,6 +76,7 @@ ScrollbarAnimationController::ScrollbarAnimationController( opacity_(initial_opacity), show_scrollbars_on_scroll_gesture_(true), need_thinning_animation_(true), + need_fade_animation_(!client->IsFluentScrollbar()), is_mouse_down_(false), tickmarks_showing_(false) { vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create( @@ -119,6 +121,14 @@ void ScrollbarAnimationController::StopAnimation() { void ScrollbarAnimationController::PostDelayedAnimation( AnimationChange animation_change) { + // In contrast to Aura overlay scrollbars, Fluent overlay scrollbars + // should not fade out completely. After the initial paint, they remain on the + // screen in the minimal (thin) mode by default and can expand/transition to + // the full (thick) mode. The minimal <-> full mode thinning animation is + // controlled by SingleScrollbarAnimationControllerThinning. + if (!need_fade_animation_) + return; + animation_change_ = animation_change; delayed_scrollbar_animation_.Cancel(); delayed_scrollbar_animation_.Reset( diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h index 5306f0870de..ce4a3f92197 100644 --- a/chromium/cc/input/scrollbar_animation_controller.h +++ b/chromium/cc/input/scrollbar_animation_controller.h @@ -27,6 +27,7 @@ class CC_EXPORT ScrollbarAnimationControllerClient { virtual void SetNeedsAnimateForScrollbarAnimation() = 0; virtual void DidChangeScrollbarVisibility() = 0; virtual ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const = 0; + virtual bool IsFluentScrollbar() const = 0; protected: virtual ~ScrollbarAnimationControllerClient() {} @@ -156,6 +157,9 @@ class CC_EXPORT ScrollbarAnimationController { const bool show_scrollbars_on_scroll_gesture_; const bool need_thinning_animation_; + // Controls whether an overlay scrollbar should fade in/out. Should be True + // for Aura overlay scrollbars and False for Fluent overlay scrollbars. + const bool need_fade_animation_; bool is_mouse_down_; diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc index 0d4a4a54b50..6069fc44543 100644 --- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc +++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc @@ -34,8 +34,9 @@ const int kThumbThickness = 10; class MockScrollbarAnimationControllerClient : public ScrollbarAnimationControllerClient { public: - explicit MockScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl) - : host_impl_(host_impl) {} + explicit MockScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl, + bool is_fluent) + : host_impl_(host_impl), is_fluent_(is_fluent) {} ~MockScrollbarAnimationControllerClient() override = default; void PostDelayedScrollbarAnimationTask(base::OnceClosure start_fade, @@ -49,6 +50,7 @@ class MockScrollbarAnimationControllerClient return host_impl_->ScrollbarsFor(scroll_element_id); } MOCK_METHOD0(DidChangeScrollbarVisibility, void()); + bool IsFluentScrollbar() const override { return is_fluent_; } base::OnceClosure& start_fade() { return start_fade_; } base::TimeDelta& delay() { return delay_; } @@ -57,13 +59,15 @@ class MockScrollbarAnimationControllerClient base::OnceClosure start_fade_; base::TimeDelta delay_; raw_ptr<LayerTreeHostImpl> host_impl_; + bool is_fluent_; }; class ScrollbarAnimationControllerAuraOverlayTest : public LayerTreeImplTestBase, public testing::Test { public: - ScrollbarAnimationControllerAuraOverlayTest() : client_(host_impl()) {} + explicit ScrollbarAnimationControllerAuraOverlayTest(bool is_fluent = false) + : client_(host_impl(), is_fluent) {} void ExpectScrollbarsOpacity(float opacity) { EXPECT_FLOAT_EQ(opacity, v_scrollbar_layer_->Opacity()); @@ -153,6 +157,19 @@ class ScrollbarAnimationControllerAuraOverlayTest NiceMock<MockScrollbarAnimationControllerClient> client_; }; +class ScrollbarAnimationControllerFluentOverlayTest + : public ScrollbarAnimationControllerAuraOverlayTest { + public: + ScrollbarAnimationControllerFluentOverlayTest() + : ScrollbarAnimationControllerAuraOverlayTest(/* is_fluent */ true) {} + + void SetUp() override { + ScrollbarAnimationControllerAuraOverlayTest::SetUp(); + // Mock initial call for did request show on page load. + scrollbar_controller_->DidRequestShow(); + } +}; + // Check initialization of scrollbar. Should start off invisible and thin. TEST_F(ScrollbarAnimationControllerAuraOverlayTest, Idle) { ExpectScrollbarsOpacity(0); @@ -1291,6 +1308,52 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TickmakrsShowHide) { EXPECT_EQ(kFadeDelay, client_.delay()); } +TEST_F(ScrollbarAnimationControllerFluentOverlayTest, + FluentScrollbarMinimalModeByDefault) { + // An fade out animation should have not been enqueued. Scrollbar stays in + // the minimal (thin) mode. + EXPECT_TRUE(client_.start_fade().is_null()); + EXPECT_FLOAT_EQ(kIdleThicknessScale, + v_scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(kIdleThicknessScale, + h_scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); + ExpectScrollbarsOpacity(1.f); +} + +TEST_F(ScrollbarAnimationControllerFluentOverlayTest, + FluentScrollbarMinimalModeOnMouseLeave) { + // Move mouse inside scroller. + scrollbar_controller_->DidMouseMove(gfx::PointF(50, 50)); + EXPECT_TRUE(client_.start_fade().is_null()); + ExpectScrollbarsOpacity(1.f); + + // Trigger mouse leave to check that Fluent overlay scrollbars don't fade out. + scrollbar_controller_->DidMouseLeave(); + + // An fade out animation should have not been enqueued. Scrollbar stays in + // the minimal (thin) mode. + EXPECT_TRUE(client_.start_fade().is_null()); + EXPECT_FLOAT_EQ(kIdleThicknessScale, + v_scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(kIdleThicknessScale, + h_scrollbar_layer_->thumb_thickness_scale_factor()); + ExpectScrollbarsOpacity(1.f); +} + +TEST_F(ScrollbarAnimationControllerFluentOverlayTest, + FluentScrollbarMinimalModeOnWillUpdateScroll) { + // Scrollbar should be visible on scroll will update. + scrollbar_controller_->WillUpdateScroll(); + + // An fade out animation should have not been enqueued. Scrollbar stays in + // the minimal (thin) mode. + EXPECT_TRUE(client_.start_fade().is_null()); + EXPECT_FLOAT_EQ(kIdleThicknessScale, + v_scrollbar_layer_->thumb_thickness_scale_factor()); + ExpectScrollbarsOpacity(1.f); +} + class ScrollbarAnimationControllerAndroidTest : public LayerTreeImplTestBase, public testing::Test, @@ -1314,6 +1377,7 @@ class ScrollbarAnimationControllerAndroidTest return host_impl()->ScrollbarsFor(scroll_element_id); } void DidChangeScrollbarVisibility() override {} + bool IsFluentScrollbar() const override { return false; } protected: void SetUp() override { diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc index e9e7b7f2672..1c5510023c6 100644 --- a/chromium/cc/input/scrollbar_controller.cc +++ b/chromium/cc/input/scrollbar_controller.cc @@ -118,23 +118,20 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown( if (scrollbar_part == ScrollbarPart::THUMB || perform_jump_click_on_track) { drag_state_ = DragState(); bool clipped = false; + drag_state_->drag_origin = - GetScrollbarRelativePosition(position_in_widget, &clipped); - // If the point were clipped we shouldn't have hit tested to a valid part. + perform_jump_click_on_track + ? DragOriginForJumpClick(scrollbar) + : GetScrollbarRelativePosition(position_in_widget, &clipped); + + // If the point were clipped we shouldn't have hit tested to a valid + // part. DCHECK(!clipped); // Record the current scroller offset. This will be needed to snap the // thumb back to its original position if the pointer moves too far away - // from the track during a thumb drag. Additionally, if a thumb drag is - // being initiated *after* a jump click, scroll_position_at_start_ needs - // to account for that. - const float jump_click_thumb_drag_delta = - scrollbar->orientation() == ScrollbarOrientation::HORIZONTAL - ? scroll_result.scroll_delta.x() - : scroll_result.scroll_delta.y(); - drag_state_->scroll_position_at_start_ = - scrollbar->current_pos() + - (perform_jump_click_on_track ? jump_click_thumb_drag_delta : 0); + // from the track during a thumb drag. + drag_state_->scroll_position_at_start_ = scrollbar->current_pos(); drag_state_->scroller_length_at_previous_move = scrollbar->scroll_layer_length(); } @@ -145,19 +142,37 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown( // have the potential of initiating an autoscroll (if held down for long // enough). DCHECK(scrollbar_part != ScrollbarPart::THUMB); - cancelable_autoscroll_task_ = - std::make_unique<base::CancelableOnceClosure>(base::BindOnce( - &ScrollbarController::StartAutoScrollAnimation, - base::Unretained(this), - InitialDeltaToAutoscrollVelocity(scroll_result.scroll_delta), - scrollbar_part)); - layer_tree_host_impl_->GetTaskRunner()->PostDelayedTask( - FROM_HERE, cancelable_autoscroll_task_->callback(), - kInitialAutoscrollTimerDelay); + autoscroll_state_ = AutoScrollState(); + autoscroll_state_->velocity = + InitialDeltaToAutoscrollVelocity(scroll_result.scroll_delta); + autoscroll_state_->pressed_scrollbar_part = scrollbar_part; + PostAutoscrollTask(kInitialAutoscrollTimerDelay); } return scroll_result; } +void ScrollbarController::PostAutoscrollTask(const base::TimeDelta delay) { + cancelable_autoscroll_task_ = + std::make_unique<base::CancelableOnceClosure>(base::BindOnce( + &ScrollbarController::StartAutoScroll, base::Unretained(this))); + layer_tree_host_impl_->GetTaskRunner()->PostDelayedTask( + FROM_HERE, cancelable_autoscroll_task_->callback(), delay); +} + +gfx::PointF ScrollbarController::DragOriginForJumpClick( + const ScrollbarLayerImplBase* scrollbar) const { + // If the user initiated a jump click, create an artificial drag origin to the + // middle of the thumb's current position. This is to simulate a jump click as + // though the user had initiated a drag normally and pulled the thumb down to + // the jump click position. This also keeps consistency with + // scroll_position_at_start_ which is used both to calculate scroll positions + // as well as for snapping back to origin if the user moves their mouse away. + gfx::Rect thumb = scrollbar->ComputeThumbQuadRect(); + return scrollbar->orientation() == ScrollbarOrientation::HORIZONTAL + ? gfx::PointF(thumb.x() + thumb.width() / 2, 0) + : gfx::PointF(0, thumb.y() + thumb.height() / 2); +} + bool ScrollbarController::SnapToDragOrigin( const gfx::PointF pointer_position_in_widget) const { // Consult the ScrollbarTheme to check if thumb snapping is supported on the @@ -450,6 +465,9 @@ float ScrollbarController::GetScrollerToScrollbarRatio() const { : thumb_rect.width(); float viewport_length = GetViewportLength(); + if (scrollbar_track_length == scrollbar_thumb_length) + return 0; + return (scroll_layer_length - viewport_length) / (scrollbar_track_length - scrollbar_thumb_length); } @@ -465,18 +483,36 @@ void ScrollbarController::ResetState() { } } +void ScrollbarController::DidRegisterScrollbar( + ElementId element_id, + ScrollbarOrientation orientation) { + if (autoscroll_state_.has_value() && + captured_scrollbar_metadata_->scroll_element_id == element_id && + captured_scrollbar_metadata_->orientation == orientation && + autoscroll_state_->status == AutoScrollStatus::AUTOSCROLL_READY) { + // This is necessary, as when the scrollbar is being registered the layer + // tree will not yet have synced its layer properties and cannot update + // scrollbar geometries yet. We need to wait until the sync is over + PostAutoscrollTask(base::TimeDelta::Min()); + } +} + void ScrollbarController::DidUnregisterScrollbar( ElementId element_id, ScrollbarOrientation orientation) { - if (captured_scrollbar_metadata_.has_value() && + if (autoscroll_state_.has_value() && captured_scrollbar_metadata_->scroll_element_id == element_id && - captured_scrollbar_metadata_->orientation == orientation) - ResetState(); + captured_scrollbar_metadata_->orientation == orientation && + autoscroll_state_->status == AutoScrollStatus::AUTOSCROLL_SCROLLING) { + layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); + autoscroll_state_->status = AutoScrollStatus::AUTOSCROLL_READY; + } } void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { if (!autoscroll_state_.has_value() || - !captured_scrollbar_metadata_.has_value()) + !captured_scrollbar_metadata_.has_value() || + autoscroll_state_->status != AutoScrollStatus::AUTOSCROLL_SCROLLING) return; layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); @@ -525,8 +561,7 @@ void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { const float scroll_layer_length = scrollbar->scroll_layer_length(); if (autoscroll_state_->scroll_layer_length != scroll_layer_length) { layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); - StartAutoScrollAnimation(autoscroll_state_->velocity, - autoscroll_state_->pressed_scrollbar_part); + StartAutoScrollAnimation(); } } @@ -542,8 +577,7 @@ void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { !layer_tree_host_impl_->mutator_host()->IsElementAnimating( scrollbar->scroll_element_id())) { // Start animating if pointer re-enters the bounds. - StartAutoScrollAnimation(autoscroll_state_->velocity, - autoscroll_state_->pressed_scrollbar_part); + StartAutoScrollAnimation(); } } @@ -558,15 +592,26 @@ float ScrollbarController::InitialDeltaToAutoscrollVelocity( return delta * kAutoscrollMultiplier; } -void ScrollbarController::StartAutoScrollAnimation( - const float velocity, - ScrollbarPart pressed_scrollbar_part) { +void ScrollbarController::StartAutoScroll() { + DCHECK(autoscroll_state_.has_value()); + + if (ScrollbarLayer()) { + autoscroll_state_->status = AutoScrollStatus::AUTOSCROLL_SCROLLING; + StartAutoScrollAnimation(); + } else { + autoscroll_state_->status = AutoScrollStatus::AUTOSCROLL_READY; + } +} + +void ScrollbarController::StartAutoScrollAnimation() { // Autoscroll and thumb drag are mutually exclusive. Both can't be active at // the same time. DCHECK(!drag_state_.has_value()); DCHECK(captured_scrollbar_metadata_.has_value()); - DCHECK_NE(velocity, 0); + DCHECK(autoscroll_state_.has_value()); DCHECK(ScrollbarLayer()); + DCHECK_EQ(autoscroll_state_->status, AutoScrollStatus::AUTOSCROLL_SCROLLING); + DCHECK_NE(autoscroll_state_->velocity, 0); // scroll_node is set up while handling GSB. If there's no node to scroll, we // don't need to create any animation for it. @@ -589,23 +634,20 @@ void ScrollbarController::StartAutoScrollAnimation( // Negative scroll velocity indicates backwards scrolling whereas a positive // value indicates forwards scrolling. const float target_offset_in_orientation = - velocity < 0 ? 0 : scroll_layer_length; + autoscroll_state_->velocity < 0 ? 0 : scroll_layer_length; const gfx::PointF target_offset_2d = scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::PointF(current_offset.x(), target_offset_in_orientation) : gfx::PointF(target_offset_in_orientation, current_offset.y()); - autoscroll_state_ = AutoScrollState(); - autoscroll_state_->velocity = velocity; autoscroll_state_->scroll_layer_length = scroll_layer_length; - autoscroll_state_->pressed_scrollbar_part = pressed_scrollbar_part; - autoscroll_state_->direction = velocity < 0 + autoscroll_state_->direction = autoscroll_state_->velocity < 0 ? AutoScrollDirection::AUTOSCROLL_BACKWARD : AutoScrollDirection::AUTOSCROLL_FORWARD; layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); layer_tree_host_impl_->AutoScrollAnimationCreate( - *scroll_node, target_offset_2d, std::abs(velocity)); + *scroll_node, target_offset_2d, std::abs(autoscroll_state_->velocity)); } // Performs hit test and prepares scroll deltas that will be used by GSE. @@ -620,7 +662,8 @@ InputHandlerPointerResult ScrollbarController::HandlePointerUp( // TODO(arakeri): This needs to be moved to ScrollOffsetAnimationsImpl as it // has knowledge about what type of animation is running. crbug.com/976353 // Only abort the animation if it is an "autoscroll" animation. - if (autoscroll_state_.has_value()) + if (autoscroll_state_.has_value() && + autoscroll_state_->status == AutoScrollStatus::AUTOSCROLL_SCROLLING) layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); ResetState(); diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h index aa5d019c7da..fdaf34df2d1 100644 --- a/chromium/cc/input/scrollbar_controller.h +++ b/chromium/cc/input/scrollbar_controller.h @@ -10,6 +10,7 @@ #include "base/cancelable_callback.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" +#include "base/time/time.h" #include "cc/cc_export.h" #include "cc/input/input_handler.h" #include "cc/input/scrollbar.h" @@ -149,6 +150,8 @@ class CC_EXPORT ScrollbarController { return cancelable_autoscroll_task_ != nullptr; } bool ScrollbarScrollIsActive() const { return scrollbar_scroll_is_active_; } + void DidRegisterScrollbar(ElementId element_id, + ScrollbarOrientation orientation); void DidUnregisterScrollbar(ElementId element_id, ScrollbarOrientation orientation); ScrollbarLayerImplBase* ScrollbarLayer() const; @@ -161,16 +164,33 @@ class CC_EXPORT ScrollbarController { ThumbDragAfterJumpClick); FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest, AbortAnimatedScrollBeforeStartingAutoscroll); + FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest, + AutoscrollOnDeletedScrollbar); + FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest, + ScrollOnLargeThumb); // "Autoscroll" here means the continuous scrolling that occurs when the // pointer is held down on a hit-testable area of the scrollbar such as an // arrows of the track itself. enum class AutoScrollDirection { AUTOSCROLL_FORWARD, AUTOSCROLL_BACKWARD }; + enum class AutoScrollStatus { + // For when the 250ms delay before an autoscroll starts animating has not + // yet elapsed + AUTOSCROLL_WAITING, + // For when the delay has elapsed, but the autoscroll cannot animate for + // some reason (the scrollbar being unregistered) + AUTOSCROLL_READY, + // For when the autoscroll is animating + AUTOSCROLL_SCROLLING + }; + struct CC_EXPORT AutoScrollState { // Can only be either AUTOSCROLL_FORWARD or AUTOSCROLL_BACKWARD. AutoScrollDirection direction = AutoScrollDirection::AUTOSCROLL_FORWARD; + AutoScrollStatus status = AutoScrollStatus::AUTOSCROLL_WAITING; + // Stores the autoscroll velocity. The sign is used to set the "direction". float velocity = 0.f; @@ -209,12 +229,17 @@ class CC_EXPORT ScrollbarController { ScrollbarOrientation orientation; }; - // "velocity" here is calculated based on the initial scroll delta (See - // InitialDeltaToAutoscrollVelocity). This value carries a "sign" which is - // needed to determine whether we should set up the autoscrolling in the - // forwards or the backwards direction. - void StartAutoScrollAnimation(float velocity, - ScrollbarPart pressed_scrollbar_part); + // Posts an autoscroll task based on the autoscroll state, with the given + // delay + void PostAutoscrollTask(const base::TimeDelta delay); + + // Initiates an autoscroll, setting the necessary status and starting the + // animation, if possible + void StartAutoScroll(); + + // Starts/restarts an autoscroll animation based off of the information in + // autoscroll_state_ + void StartAutoScrollAnimation(); // Returns the DSF based on whether use-zoom-for-dsf is enabled. float ScreenSpaceScaleFactor() const; @@ -250,8 +275,13 @@ class CC_EXPORT ScrollbarController { gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget, bool* clipped) const; - // Decides if the scroller should snap to the offset that it was originally at - // (i.e the offset before the thumb drag). + // Computes an aritificial drag origin for jump clicks, to give the scrollbar + // a proper place to snap back to on a jump click then drag + gfx::PointF DragOriginForJumpClick( + const ScrollbarLayerImplBase* scrollbar) const; + + // Decides if the scroller should snap to the offset that it was + // originally at (i.e the offset before the thumb drag). bool SnapToDragOrigin(const gfx::PointF pointer_position_in_widget) const; // Decides whether a track autoscroll should be aborted (or restarted) due to @@ -298,7 +328,7 @@ class CC_EXPORT ScrollbarController { absl::optional<CapturedScrollbarMetadata> captured_scrollbar_metadata_; // Holds information pertaining to autoscrolling. This member is empty if and - // only if an autoscroll is *not* in progress. + // only if an autoscroll is *not* in progress or scheduled absl::optional<AutoScrollState> autoscroll_state_; // Holds information pertaining to thumb drags. Useful while making decisions diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc index 6efa8d18db0..ff0221ea9e5 100644 --- a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc +++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc @@ -39,6 +39,7 @@ class MockSingleScrollbarAnimationControllerClient ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override { return host_impl_->ScrollbarsFor(scroll_element_id); } + bool IsFluentScrollbar() const override { return false; } MOCK_METHOD2(PostDelayedScrollbarAnimationTask, void(base::OnceClosure start_fade, base::TimeDelta delay)); diff --git a/chromium/cc/input/threaded_input_handler.cc b/chromium/cc/input/threaded_input_handler.cc index 008fd647130..be15f495eaa 100644 --- a/chromium/cc/input/threaded_input_handler.cc +++ b/chromium/cc/input/threaded_input_handler.cc @@ -289,11 +289,12 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin( // InputHander::ScrollThread::SCROLL_ON_MAIN_THREAD scroll_status.main_thread_scrolling_reasons = MainThreadScrollingReason::kNoScrollingLayer; - if (compositor_delegate_.GetSettings().is_layer_tree_for_subframe) { - // OOPIFs never have a viewport scroll node so if we can't scroll - // we need to be bubble up to the parent frame. This happens by - // returning SCROLL_IGNORED. - TRACE_EVENT_INSTANT0("cc", "Ignored - No ScrollNode (OOPIF)", + if (compositor_delegate_.GetSettings().is_for_embedded_frame) { + // OOPIFs or fenced frames never have a viewport scroll node so if we + // can't scroll we need to be bubble up to the parent frame. This happens + // by returning SCROLL_IGNORED. + TRACE_EVENT_INSTANT0("cc", + "Ignored - No ScrollNode (OOPIF or FencedFrame)", TRACE_EVENT_SCOPE_THREAD); } else { // If we didn't hit a layer above we'd usually fallback to the @@ -375,6 +376,7 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( if (!CurrentlyScrollingNode()) return InputHandlerScrollResult(); + const ScrollNode& scroll_node = *CurrentlyScrollingNode(); last_scroll_update_state_ = *scroll_state; // Snap on update if interacting with the scrollbar track or arrow buttons. @@ -387,7 +389,7 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( } gfx::Vector2dF resolvedScrollDelta = ResolveScrollGranularityToPixels( - *CurrentlyScrollingNode(), + scroll_node, gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y()), scroll_state->delta_granularity()); @@ -406,7 +408,7 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( compositor_delegate_.AccumulateScrollDeltaForTracing( gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y())); - compositor_delegate_.WillScrollContent(CurrentlyScrollingNode()->element_id); + compositor_delegate_.WillScrollContent(scroll_node.element_id); float initial_top_controls_offset = compositor_delegate_.GetImplDeprecated() .browser_controls_manager() @@ -418,10 +420,12 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( bool did_scroll_y = scroll_state->caused_scroll_y(); did_scroll_x_for_scroll_gesture_ |= did_scroll_x; did_scroll_y_for_scroll_gesture_ |= did_scroll_y; + delta_consumed_for_scroll_gesture_ |= + scroll_state->delta_consumed_for_scroll_sequence(); bool did_scroll_content = did_scroll_x || did_scroll_y; if (did_scroll_content) { bool is_animated_scroll = ShouldAnimateScroll(*scroll_state); - compositor_delegate_.DidScrollContent(CurrentlyScrollingNode()->element_id, + compositor_delegate_.DidScrollContent(scroll_node.element_id, is_animated_scroll); } else { overscroll_delta_for_main_thread_ += @@ -437,7 +441,7 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( accumulated_root_overscroll_.set_y(0); gfx::Vector2dF unused_root_delta; - if (GetViewport().ShouldScroll(*CurrentlyScrollingNode())) { + if (GetViewport().ShouldScroll(scroll_node)) { unused_root_delta = gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y()); } @@ -471,11 +475,15 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate( UpdateRootLayerStateForSynchronousInputHandler(); } - scroll_result.current_visual_offset = - GetVisualScrollOffset(*CurrentlyScrollingNode()); + scroll_result.current_visual_offset = GetVisualScrollOffset(scroll_node); float scale_factor = ActiveTree().page_scale_factor_for_scroll(); scroll_result.current_visual_offset.Scale(scale_factor); + if (base::FeatureList::IsEnabled(features::kScrollUnification) && + !GetScrollTree().CanRealizeScrollsOnCompositor(scroll_node)) { + scroll_result.needs_main_thread_repaint = true; + } + // Run animations which need to respond to updated scroll offset. compositor_delegate_.GetImplDeprecated().mutator_host()->TickScrollAnimations( compositor_delegate_.GetImplDeprecated() @@ -1124,6 +1132,12 @@ void ThreadedInputHandler::RootLayerStateMayHaveChanged() { UpdateRootLayerStateForSynchronousInputHandler(); } +void ThreadedInputHandler::DidRegisterScrollbar( + ElementId scroll_element_id, + ScrollbarOrientation orientation) { + scrollbar_controller_->DidRegisterScrollbar(scroll_element_id, orientation); +} + void ThreadedInputHandler::DidUnregisterScrollbar( ElementId scroll_element_id, ScrollbarOrientation orientation) { @@ -1182,10 +1196,7 @@ ActivelyScrollingType ThreadedInputHandler::GetActivelyScrollingType() const { if (!last_scroll_update_state_) return ActivelyScrollingType::kNone; - bool did_scroll_content = - did_scroll_x_for_scroll_gesture_ || did_scroll_y_for_scroll_gesture_; - - if (!did_scroll_content) + if (!delta_consumed_for_scroll_gesture_) return ActivelyScrollingType::kNone; if (ShouldAnimateScroll(last_scroll_update_state_.value())) @@ -2157,6 +2168,7 @@ void ThreadedInputHandler::ClearCurrentlyScrollingNode() { accumulated_root_overscroll_ = gfx::Vector2dF(); did_scroll_x_for_scroll_gesture_ = false; did_scroll_y_for_scroll_gesture_ = false; + delta_consumed_for_scroll_gesture_ = false; scroll_animating_snap_target_ids_ = TargetSnapAreaElementIds(); latched_scroll_type_.reset(); last_scroll_update_state_.reset(); @@ -2249,4 +2261,9 @@ bool ThreadedInputHandler::ScrollbarScrollIsActive() { return scrollbar_controller_->ScrollbarScrollIsActive(); } +void ThreadedInputHandler::SetDeferBeginMainFrame( + bool defer_begin_main_frame) const { + compositor_delegate_.SetDeferBeginMainFrame(defer_begin_main_frame); +} + } // namespace cc diff --git a/chromium/cc/input/threaded_input_handler.h b/chromium/cc/input/threaded_input_handler.h index ff554e8562b..08a356852ae 100644 --- a/chromium/cc/input/threaded_input_handler.h +++ b/chromium/cc/input/threaded_input_handler.h @@ -106,6 +106,7 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler, void ScrollEndForSnapFling(bool did_finish) override; void NotifyInputEvent() override; bool ScrollbarScrollIsActive() override; + void SetDeferBeginMainFrame(bool defer_begin_main_frame) const override; // =========== InputDelegateForCompositor Interface - This section implements // the interface that LayerTreeHostImpl uses to communicate with the input @@ -118,6 +119,8 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler, void DidCommit() override; void DidActivatePendingTree() override; void RootLayerStateMayHaveChanged() override; + void DidRegisterScrollbar(ElementId scroll_element_id, + ScrollbarOrientation orientation) override; void DidUnregisterScrollbar(ElementId scroll_element_id, ScrollbarOrientation orientation) override; void ScrollOffsetAnimationFinished() override; @@ -183,6 +186,8 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler, AutoscrollOnDeletedScrollbar); FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest, ThumbDragAfterJumpClick); + FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest, + ScrollOnLargeThumb); FRIEND_TEST_ALL_PREFIXES(LayerTreeHostImplTest, AutoscrollTaskAbort); // This method gets the scroll offset for a regular scroller, or the combined @@ -424,6 +429,11 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler, bool did_scroll_x_for_scroll_gesture_ = false; bool did_scroll_y_for_scroll_gesture_ = false; + // did_scroll_x/y_for_scroll_gesture_ is true when contents consume the delta, + // but delta_consumed_for_scroll_gesture_ can be true when only browser + // controls consume all the delta. + bool delta_consumed_for_scroll_gesture_ = false; + // TODO(bokan): Mac doesn't yet have smooth scrolling for wheel; however, to // allow consistency in tests we use this bit to override that decision. // https://crbug.com/574283. diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index ad9561ec843..bf883bd1e01 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -370,7 +370,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( display_item_list->Finalize(); auto* ri = raster_context_provider->RasterInterface(); - constexpr GLuint background_color = SkColorSetARGB(0, 0, 0, 0); + constexpr SkColor4f background_color = SkColors::kTransparent; constexpr GLuint msaa_sample_count = -1; constexpr bool can_use_lcd_text = true; ri->BeginRasterCHROMIUM(background_color, needs_clear, msaa_sample_count, @@ -685,7 +685,8 @@ void HeadsUpDisplayLayerImpl::DrawText(PaintCanvas* canvas, void HeadsUpDisplayLayerImpl::DrawGraphBackground(PaintCanvas* canvas, PaintFlags* flags, const SkRect& bounds) const { - flags->setColor(DebugColors::HUDBackgroundColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags->setColor(DebugColors::HUDBackgroundColor().toSkColor()); canvas->drawRect(bounds, *flags); } @@ -693,7 +694,8 @@ void HeadsUpDisplayLayerImpl::DrawGraphLines(PaintCanvas* canvas, PaintFlags* flags, const SkRect& bounds) const { // Draw top and bottom line. - flags->setColor(DebugColors::HUDSeparatorLineColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags->setColor(DebugColors::HUDSeparatorLineColor().toSkColor()); canvas->drawLine(bounds.left(), bounds.top() - 1, bounds.right(), bounds.top() - 1, *flags); canvas->drawLine(bounds.left(), bounds.bottom(), bounds.right(), @@ -755,11 +757,13 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay( } VLOG(1) << value_text; - flags.setColor(DebugColors::HUDTitleColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::HUDTitleColor().toSkColor()); DrawText(canvas, flags, title, TextAlign::kLeft, kTitleFontHeight, title_bounds.left(), title_bounds.bottom()); - flags.setColor(DebugColors::FPSDisplayTextAndGraphColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::FPSDisplayTextAndGraphColor().toSkColor()); DrawText(canvas, flags, value_text, TextAlign::kRight, kFontHeight, text_bounds.right(), text_bounds.bottom()); @@ -786,13 +790,15 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay( flags.setStyle(PaintFlags::kStroke_Style); flags.setStrokeWidth(1); - flags.setColor(DebugColors::FPSDisplaySuccessfulFrame()); + // TODO(crbug/1308932): Remove all instances of toSkColor below and make all + // SkColor4f. + flags.setColor(DebugColors::FPSDisplaySuccessfulFrame().toSkColor()); canvas->drawPath(good_path, flags); - flags.setColor(DebugColors::FPSDisplayDroppedFrame()); + flags.setColor(DebugColors::FPSDisplayDroppedFrame().toSkColor()); canvas->drawPath(dropped_path, flags); - flags.setColor(DebugColors::FPSDisplayMissedFrame()); + flags.setColor(DebugColors::FPSDisplayMissedFrame().toSkColor()); canvas->drawPath(partial_path, flags); return area; @@ -822,11 +828,13 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(PaintCanvas* canvas, SkPoint stat2_pos = SkPoint::Make(left + width - kPadding - 1, top + 2 * kPadding + 3 * kFontHeight); - flags.setColor(DebugColors::HUDTitleColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::HUDTitleColor().toSkColor()); DrawText(canvas, flags, "GPU memory", TextAlign::kLeft, kTitleFontHeight, title_pos); - flags.setColor(DebugColors::MemoryDisplayTextColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::MemoryDisplayTextColor().toSkColor()); std::string text = base::StringPrintf( "%6.1f MB used", memory_entry_.total_bytes_used / kMegabyte); DrawText(canvas, flags, text, TextAlign::kRight, kFontHeight, stat1_pos); @@ -916,7 +924,8 @@ SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(PaintCanvas* canvas, SkPoint gpu_status_pos = SkPoint::Make(left + width - kPadding, top + 2 * kFontHeight + 2 * kPadding); - flags.setColor(DebugColors::HUDTitleColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::HUDTitleColor().toSkColor()); DrawText(canvas, flags, "GPU raster", TextAlign::kLeft, kTitleFontHeight, left + kPadding, top + kFontHeight + kPadding); flags.setColor(color); @@ -995,6 +1004,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( std::string label_text; switch (debug_rects[i].type) { + // TODO(crbug/1308932): Remove all instances of toSkColor below and make + // all SkColor4f. case LAYOUT_SHIFT_RECT_TYPE: new_layout_shift_rects.push_back(debug_rects[i]); continue; @@ -1002,56 +1013,65 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( new_paint_rects.push_back(debug_rects[i]); continue; case PROPERTY_CHANGED_RECT_TYPE: - stroke_color = DebugColors::PropertyChangedRectBorderColor(); - fill_color = DebugColors::PropertyChangedRectFillColor(); + stroke_color = + DebugColors::PropertyChangedRectBorderColor().toSkColor(); + fill_color = DebugColors::PropertyChangedRectFillColor().toSkColor(); stroke_width = DebugColors::PropertyChangedRectBorderWidth(); break; case SURFACE_DAMAGE_RECT_TYPE: - stroke_color = DebugColors::SurfaceDamageRectBorderColor(); - fill_color = DebugColors::SurfaceDamageRectFillColor(); + stroke_color = DebugColors::SurfaceDamageRectBorderColor().toSkColor(); + fill_color = DebugColors::SurfaceDamageRectFillColor().toSkColor(); stroke_width = DebugColors::SurfaceDamageRectBorderWidth(); break; case SCREEN_SPACE_RECT_TYPE: - stroke_color = DebugColors::ScreenSpaceLayerRectBorderColor(); - fill_color = DebugColors::ScreenSpaceLayerRectFillColor(); + stroke_color = + DebugColors::ScreenSpaceLayerRectBorderColor().toSkColor(); + fill_color = DebugColors::ScreenSpaceLayerRectFillColor().toSkColor(); stroke_width = DebugColors::ScreenSpaceLayerRectBorderWidth(); break; case TOUCH_EVENT_HANDLER_RECT_TYPE: - stroke_color = DebugColors::TouchEventHandlerRectBorderColor(); - fill_color = DebugColors::TouchEventHandlerRectFillColor(); + stroke_color = + DebugColors::TouchEventHandlerRectBorderColor().toSkColor(); + fill_color = DebugColors::TouchEventHandlerRectFillColor().toSkColor(); stroke_width = DebugColors::TouchEventHandlerRectBorderWidth(); label_text = "touch event listener: "; label_text.append(TouchActionToString(debug_rects[i].touch_action)); break; case WHEEL_EVENT_HANDLER_RECT_TYPE: - stroke_color = DebugColors::WheelEventHandlerRectBorderColor(); - fill_color = DebugColors::WheelEventHandlerRectFillColor(); + stroke_color = + DebugColors::WheelEventHandlerRectBorderColor().toSkColor(); + fill_color = DebugColors::WheelEventHandlerRectFillColor().toSkColor(); stroke_width = DebugColors::WheelEventHandlerRectBorderWidth(); label_text = "mousewheel event listener"; break; case SCROLL_EVENT_HANDLER_RECT_TYPE: - stroke_color = DebugColors::ScrollEventHandlerRectBorderColor(); - fill_color = DebugColors::ScrollEventHandlerRectFillColor(); + stroke_color = + DebugColors::ScrollEventHandlerRectBorderColor().toSkColor(); + fill_color = DebugColors::ScrollEventHandlerRectFillColor().toSkColor(); stroke_width = DebugColors::ScrollEventHandlerRectBorderWidth(); label_text = "scroll event listener"; break; case NON_FAST_SCROLLABLE_RECT_TYPE: - stroke_color = DebugColors::NonFastScrollableRectBorderColor(); - fill_color = DebugColors::NonFastScrollableRectFillColor(); + stroke_color = + DebugColors::NonFastScrollableRectBorderColor().toSkColor(); + fill_color = DebugColors::NonFastScrollableRectFillColor().toSkColor(); stroke_width = DebugColors::NonFastScrollableRectBorderWidth(); label_text = "repaints on scroll"; break; case MAIN_THREAD_SCROLLING_REASON_RECT_TYPE: - stroke_color = DebugColors::MainThreadScrollingReasonRectBorderColor(); - fill_color = DebugColors::MainThreadScrollingReasonRectFillColor(); + stroke_color = + DebugColors::MainThreadScrollingReasonRectBorderColor().toSkColor(); + fill_color = + DebugColors::MainThreadScrollingReasonRectFillColor().toSkColor(); stroke_width = DebugColors::MainThreadScrollingReasonRectBorderWidth(); label_text = "main thread scrolling: "; label_text.append(base::ToLowerASCII(MainThreadScrollingReason::AsText( debug_rects[i].main_thread_scrolling_reasons))); break; case ANIMATION_BOUNDS_RECT_TYPE: - stroke_color = DebugColors::LayerAnimationBoundsBorderColor(); - fill_color = DebugColors::LayerAnimationBoundsFillColor(); + stroke_color = + DebugColors::LayerAnimationBoundsBorderColor().toSkColor(); + fill_color = DebugColors::LayerAnimationBoundsFillColor().toSkColor(); stroke_width = DebugColors::LayerAnimationBoundsBorderWidth(); label_text = "animation bounds"; break; @@ -1067,11 +1087,14 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( } if (paint_rects_fade_step_ > 0) { paint_rects_fade_step_--; - for (size_t i = 0; i < paint_rects_.size(); ++i) { - DrawDebugRect(canvas, &flags, paint_rects_[i], - DebugColors::PaintRectBorderColor(paint_rects_fade_step_), - DebugColors::PaintRectFillColor(paint_rects_fade_step_), - DebugColors::PaintRectBorderWidth(), ""); + for (auto& paint_rect : paint_rects_) { + // TODO(crbug/1308932): Remove all instances of toSkColor below and make + // all SkColor4f. + DrawDebugRect( + canvas, &flags, paint_rect, + DebugColors::PaintRectBorderColor(paint_rects_fade_step_).toSkColor(), + DebugColors::PaintRectFillColor(paint_rects_fade_step_).toSkColor(), + DebugColors::PaintRectBorderWidth(), ""); } } if (new_layout_shift_rects.size()) { @@ -1080,11 +1103,14 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( } if (layout_shift_rects_fade_step_ > 0) { layout_shift_rects_fade_step_--; - for (size_t i = 0; i < layout_shift_debug_rects_.size(); ++i) { + for (auto& layout_shift_debug_rect : layout_shift_debug_rects_) { + // TODO(crbug/1308932): Remove all instances of toSkColor below and make + // all SkColor4f. DrawDebugRect( - canvas, &flags, layout_shift_debug_rects_[i], - DebugColors::LayoutShiftRectBorderColor(), - DebugColors::LayoutShiftRectFillColor(layout_shift_rects_fade_step_), + canvas, &flags, layout_shift_debug_rect, + DebugColors::LayoutShiftRectBorderColor().toSkColor(), + DebugColors::LayoutShiftRectFillColor(layout_shift_rects_fade_step_) + .toSkColor(), DebugColors::LayoutShiftRectBorderWidth(), ""); } } @@ -1100,7 +1126,8 @@ int HeadsUpDisplayLayerImpl::DrawSingleMetric( bool has_value, double value) const { std::string value_str = "-"; - SkColor metrics_color = DebugColors::HUDTitleColor(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + SkColor metrics_color = DebugColors::HUDTitleColor().toSkColor(); SkColor badge_color = SK_ColorGREEN; if (has_value) { value_str = ToStringTwoDecimalPrecision(value) + info.UnitToString(); @@ -1148,7 +1175,8 @@ int HeadsUpDisplayLayerImpl::DrawSingleMetric( // Draw the label and values of the metric. PaintFlags flags; - flags.setColor(DebugColors::HUDTitleColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::HUDTitleColor().toSkColor()); DrawText(canvas, flags, name, TextAlign::kLeft, metrics_sizes.kFontHeight, left + metrics_sizes.kSidePadding + metrics_sizes.kBadgeWidth, top); flags.setColor(metrics_color); @@ -1201,11 +1229,13 @@ int HeadsUpDisplayLayerImpl::DrawSinglePercentageMetric(PaintCanvas* canvas, std::string name, double value) const { std::string value_str = "-"; - SkColor metrics_color = DebugColors::HUDTitleColor(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + SkColor metrics_color = DebugColors::HUDTitleColor().toSkColor(); value_str = ToStringTwoDecimalPrecision(value) + "%"; PaintFlags flags; - flags.setColor(DebugColors::HUDTitleColor()); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + flags.setColor(DebugColors::HUDTitleColor().toSkColor()); DrawText(canvas, flags, name, TextAlign::kLeft, metrics_sizes.kFontHeight, left + metrics_sizes.kSidePadding + metrics_sizes.kBadgeWidth, top); flags.setColor(metrics_color); diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index 5000df2f883..7e9dd9f6e9b 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -52,10 +52,10 @@ struct SameSizeAsLayer : public base::RefCounted<SameSizeAsLayer>, LayerList children; gfx::Size bounds; unsigned bitfields; - SkColor background_color; + SkColor4f background_color; TouchActionRegion touch_action_region; ElementId element_id; - void* rare_inputs; + raw_ptr<void> rare_inputs; } inputs; raw_ptr<void> layer_tree_inputs; gfx::Rect update_rect; @@ -83,7 +83,7 @@ Layer::Inputs::Inputs() contents_opaque_for_text(false), is_drawable(false), double_sided(true), - background_color(0) {} + background_color(SkColors::kTransparent) {} Layer::Inputs::~Inputs() = default; @@ -526,7 +526,7 @@ void Layer::RequestCopyOfOutput( layer_tree_host()->SetHasCopyRequest(true); } -void Layer::SetBackgroundColor(SkColor background_color) { +void Layer::SetBackgroundColor(SkColor4f background_color) { DCHECK(IsPropertyChangeAllowed()); auto& inputs = inputs_.Write(*this); if (inputs.background_color == background_color) @@ -536,9 +536,9 @@ void Layer::SetBackgroundColor(SkColor background_color) { SetNeedsCommit(); } -void Layer::SetSafeOpaqueBackgroundColor(SkColor background_color) { +void Layer::SetSafeOpaqueBackgroundColor(SkColor4f background_color) { DCHECK(IsPropertyChangeAllowed()); - SkColor opaque_color = SkColorSetA(background_color, SK_AlphaOPAQUE); + SkColor4f opaque_color = background_color.makeOpaque(); auto& inputs = EnsureLayerTreeInputs(); if (inputs.safe_opaque_background_color == opaque_color) return; @@ -546,39 +546,42 @@ void Layer::SetSafeOpaqueBackgroundColor(SkColor background_color) { SetNeedsPushProperties(); } -SkColor Layer::SafeOpaqueBackgroundColor(SkColor host_background_color) const { +SkColor4f Layer::SafeOpaqueBackgroundColor( + SkColor4f host_background_color) const { if (contents_opaque()) { if (!IsAttached() || !IsUsingLayerLists()) { // In layer tree mode, PropertyTreeBuilder should have calculated the safe // opaque background color and called SetSafeOpaqueBackgroundColor(). DCHECK(layer_tree_inputs()); - DCHECK_EQ(SkColorGetA(layer_tree_inputs()->safe_opaque_background_color), - SK_AlphaOPAQUE); + DCHECK(layer_tree_inputs()->safe_opaque_background_color.isOpaque()); return layer_tree_inputs()->safe_opaque_background_color; } // In layer list mode, the PropertyTreeBuilder algorithm doesn't apply // because it depends on the layer tree hierarchy. Instead we use // background_color() if it's not transparent, or layer_tree_host_'s // background_color(), with the alpha channel forced to be opaque. - SkColor color = background_color() == SK_ColorTRANSPARENT - ? host_background_color - : background_color(); - return SkColorSetA(color, SK_AlphaOPAQUE); + SkColor4f color = background_color() == SkColors::kTransparent + ? host_background_color + : background_color(); + return color.makeOpaque(); } - if (SkColorGetA(background_color()) == SK_AlphaOPAQUE) { + if (background_color().isOpaque()) { // The layer is not opaque while the background color is, meaning that the - // background color doesn't cover the whole layer. Use SK_ColorTRANSPARENT - // to avoid intrusive checkerboard where the layer is not covered by the - // background color. - return SK_ColorTRANSPARENT; + // background color doesn't cover the whole layer. Use + // SkColors::kTransparent to avoid intrusive checkerboard where the layer is + // not covered by the background color. + return SkColors::kTransparent; } return background_color(); } -SkColor Layer::SafeOpaqueBackgroundColor() const { - SkColor host_background_color = - IsAttached() ? layer_tree_host()->pending_commit_state()->background_color - : layer_tree_inputs()->safe_opaque_background_color; +SkColor4f Layer::SafeOpaqueBackgroundColor() const { + // TODO(crbug/1308932): Remove FromColor and make all SkColor4f. + SkColor4f host_background_color = + IsAttached() + ? SkColor4f::FromColor( + layer_tree_host()->pending_commit_state()->background_color) + : layer_tree_inputs()->safe_opaque_background_color; return SafeOpaqueBackgroundColor(host_background_color); } @@ -1201,6 +1204,7 @@ void Layer::SetCaptureBounds(viz::RegionCaptureBounds bounds) { EnsureRareInputs().capture_bounds = std::move(bounds); SetPropertyTreesNeedRebuild(); SetNeedsCommit(); + SetSubtreePropertyChanged(); } void Layer::SetWheelEventRegion(Region wheel_event_region) { @@ -1465,8 +1469,9 @@ void Layer::PushPropertiesTo(LayerImpl* layer, layer->SetElementId(inputs.element_id); layer->SetHasTransformNode(has_transform_node()); layer->SetBackgroundColor(inputs.background_color); - layer->SetSafeOpaqueBackgroundColor( - SafeOpaqueBackgroundColor(commit_state.background_color)); + // TODO(crbug/1308932): Remove FromColor and make all SkColor4f. + layer->SetSafeOpaqueBackgroundColor(SafeOpaqueBackgroundColor( + SkColor4f::FromColor(commit_state.background_color))); layer->SetBounds(inputs.bounds); layer->SetTransformTreeIndex(transform_tree_index(property_trees)); layer->SetEffectTreeIndex(effect_tree_index(property_trees)); diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index c99407a5938..588cecfa2a0 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -171,15 +171,15 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // Set and get the background color for the layer. This color is not used by // basic Layers, but subclasses may make use of it. - virtual void SetBackgroundColor(SkColor background_color); - SkColor background_color() const { + virtual void SetBackgroundColor(SkColor4f background_color); + SkColor4f background_color() const { return inputs_.Read(*this).background_color; } // For layer tree mode only. In layer list mode, client doesn't need to set // it. Sets an opaque background color for the layer, to be used in place of // the background_color() if the layer says contents_opaque() is true. - void SetSafeOpaqueBackgroundColor(SkColor background_color); + void SetSafeOpaqueBackgroundColor(SkColor4f background_color); // Returns a background color with opaqueness equal to the value of // contents_opaque(). @@ -189,13 +189,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // from background_color() and the argument host_background_color. // Otherwise, it returns something non-opaque. It prefers to return the // background_color(), but if the background_color() is opaque (and this layer - // claims to not be), then SK_ColorTRANSPARENT is returned to avoid intrusive - // checkerboard where the layer is not covered by the background_color(). - SkColor SafeOpaqueBackgroundColor(SkColor host_background_color) const; + // claims to not be), then SkColors::kTransparent is returned to avoid + // intrusive checkerboard where the layer is not covered by the + // background_color(). + SkColor4f SafeOpaqueBackgroundColor(SkColor4f host_background_color) const; // Same as the one-argument version, except that host_background_color is // layer_tree_host()->pending_commit_state()->background_color. - SkColor SafeOpaqueBackgroundColor() const; + SkColor4f SafeOpaqueBackgroundColor() const; // For layer tree mode only. // Set and get the position of this layer, relative to its parent. This is @@ -999,7 +1000,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, bool is_drawable : 1; bool double_sided : 1; - SkColor background_color; + SkColor4f background_color; TouchActionRegion touch_action_region; ElementId element_id; @@ -1053,7 +1054,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // surface that darws in a render pass. viz::SubtreeCaptureId subtree_capture_id; - SkColor safe_opaque_background_color = SK_ColorTRANSPARENT; + SkColor4f safe_opaque_background_color = SkColors::kTransparent; FilterOperations filters; FilterOperations backdrop_filters; @@ -1160,7 +1161,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, AllowRemoveForReadd& operator=(const AllowRemoveForReadd&) = delete; private: - Layer* layer_; + raw_ptr<Layer> layer_; }; bool allow_remove_for_readd_ = false; diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index f657d64f539..1e9e856c2da 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -71,8 +71,8 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, contributes_to_drawn_render_surface_(false), hit_testable_(false), is_inner_viewport_scroll_layer_(false), - background_color_(0), - safe_opaque_background_color_(0), + background_color_(SkColors::kTransparent), + safe_opaque_background_color_(SkColors::kTransparent), transform_tree_index_(kInvalidPropertyNodeId), effect_tree_index_(kInvalidPropertyNodeId), clip_tree_index_(kInvalidPropertyNodeId), @@ -228,7 +228,7 @@ bool LayerImpl::ShowDebugBorders(DebugBorderType type) const { return layer_tree_impl()->debug_state().show_debug_borders.test(type); } -void LayerImpl::GetDebugBorderProperties(SkColor* color, float* width) const { +void LayerImpl::GetDebugBorderProperties(SkColor4f* color, float* width) const { float device_scale_factor = layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1; @@ -247,7 +247,7 @@ void LayerImpl::AppendDebugBorderQuad( const gfx::Rect& quad_rect, const viz::SharedQuadState* shared_quad_state, AppendQuadsData* append_quads_data) const { - SkColor color; + SkColor4f color; float width; GetDebugBorderProperties(&color, &width); AppendDebugBorderQuad(render_pass, quad_rect, shared_quad_state, @@ -259,7 +259,7 @@ void LayerImpl::AppendDebugBorderQuad( const gfx::Rect& quad_rect, const viz::SharedQuadState* shared_quad_state, AppendQuadsData* append_quads_data, - SkColor color, + SkColor4f color, float width) const { if (!ShowDebugBorders(DebugBorderType::LAYER)) return; @@ -273,14 +273,15 @@ void LayerImpl::AppendDebugBorderQuad( gfx::Rect visible_quad_rect(quad_rect); auto* debug_border_quad = render_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>(); - debug_border_quad->SetNew( - shared_quad_state, quad_rect, visible_quad_rect, color, width); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + debug_border_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, + color.toSkColor(), width); if (contents_opaque()) { // When opaque, draw a second inner border that is thicker than the outer // border, but more transparent. static const float kFillOpacity = 0.3f; - SkColor fill_color = SkColorSetA( - color, static_cast<uint8_t>(SkColorGetA(color) * kFillOpacity)); + SkColor4f fill_color = color; + color.fA *= kFillOpacity; float fill_width = width * 3; gfx::Rect fill_rect = quad_rect; fill_rect.Inset(fill_width / 2.f); @@ -288,10 +289,11 @@ void LayerImpl::AppendDebugBorderQuad( return; gfx::Rect visible_fill_rect = gfx::IntersectRects(visible_quad_rect, fill_rect); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. auto* fill_quad = render_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>(); fill_quad->SetNew(shared_quad_state, fill_rect, visible_fill_rect, - fill_color, fill_width); + fill_color.toSkColor(), fill_width); } } @@ -569,7 +571,7 @@ bool LayerImpl::HitTestable() const { return should_hit_test; } -void LayerImpl::SetBackgroundColor(SkColor background_color) { +void LayerImpl::SetBackgroundColor(SkColor4f background_color) { if (background_color_ == background_color) return; @@ -577,7 +579,7 @@ void LayerImpl::SetBackgroundColor(SkColor background_color) { NoteLayerPropertyChanged(); } -void LayerImpl::SetSafeOpaqueBackgroundColor(SkColor background_color) { +void LayerImpl::SetSafeOpaqueBackgroundColor(SkColor4f background_color) { safe_opaque_background_color_ = background_color; } diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h index 8777e92c956..a02b814d77a 100644 --- a/chromium/cc/layers/layer_impl.h +++ b/chromium/cc/layers/layer_impl.h @@ -164,13 +164,12 @@ class CC_EXPORT LayerImpl { void SetHitTestable(bool should_hit_test); bool HitTestable() const; - void SetBackgroundColor(SkColor background_color); - SkColor background_color() const { return background_color_; } - void SetSafeOpaqueBackgroundColor(SkColor background_color); - SkColor safe_opaque_background_color() const { + void SetBackgroundColor(SkColor4f background_color); + SkColor4f background_color() const { return background_color_; } + void SetSafeOpaqueBackgroundColor(SkColor4f background_color); + SkColor4f safe_opaque_background_color() const { // Layer::SafeOpaqueBackgroundColor() should ensure this. - DCHECK_EQ(contents_opaque(), - SkColorGetA(safe_opaque_background_color_) == SK_AlphaOPAQUE); + DCHECK_EQ(contents_opaque(), safe_opaque_background_color_.isOpaque()); return safe_opaque_background_color_; } @@ -471,7 +470,7 @@ class CC_EXPORT LayerImpl { bool will_always_push_properties = false); // Get the color and size of the layer's debug border. - virtual void GetDebugBorderProperties(SkColor* color, float* width) const; + virtual void GetDebugBorderProperties(SkColor4f* color, float* width) const; void AppendDebugBorderQuad(viz::CompositorRenderPass* render_pass, const gfx::Rect& quad_rect, @@ -481,7 +480,7 @@ class CC_EXPORT LayerImpl { const gfx::Rect& quad_rect, const viz::SharedQuadState* shared_quad_state, AppendQuadsData* append_quads_data, - SkColor color, + SkColor4f color, float width) const; static float GetPreferredRasterScale( @@ -538,8 +537,8 @@ class CC_EXPORT LayerImpl { TouchActionRegion touch_action_region_; - SkColor background_color_; - SkColor safe_opaque_background_color_; + SkColor4f background_color_; + SkColor4f safe_opaque_background_color_; int transform_tree_index_; int effect_tree_index_; diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc index 73a0698f378..095e57d61a4 100644 --- a/chromium/cc/layers/layer_impl_unittest.cc +++ b/chromium/cc/layers/layer_impl_unittest.cc @@ -102,7 +102,7 @@ TEST_F(LayerImplTest, VerifyPendingLayerChangesAreTrackedProperly) { gfx::Point arbitrary_point = gfx::Point(333, 444); gfx::Rect arbitrary_rect = gfx::Rect(arbitrary_point, arbitrary_size); - SkColor arbitrary_color = SkColorSetRGB(10, 20, 30); + SkColor4f arbitrary_color{0.1f, 0.2f, 0.3f, 1.0f}; gfx::Transform arbitrary_transform; arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); FilterOperations arbitrary_filters; @@ -166,7 +166,7 @@ TEST_F(LayerImplTest, VerifyNeedsUpdateDrawProperties) { gfx::PointF arbitrary_scroll_offset( gfx::PointAtOffsetFromOrigin(arbitrary_vector2d)); gfx::Size large_size = gfx::Size(1000, 1000); - SkColor arbitrary_color = SkColorSetRGB(10, 20, 30); + SkColor4f arbitrary_color{0.1f, 0.2f, 0.3f, 1.0f}; gfx::Transform arbitrary_transform; arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); FilterOperations arbitrary_filters; diff --git a/chromium/cc/layers/layer_list_iterator.h b/chromium/cc/layers/layer_list_iterator.h index 2641c280c7f..dc7e92a20a3 100644 --- a/chromium/cc/layers/layer_list_iterator.h +++ b/chromium/cc/layers/layer_list_iterator.h @@ -9,6 +9,7 @@ #include <vector> #include "base/memory/raw_ptr.h" +#include "base/memory/raw_ptr_exclusion.h" #include "cc/cc_export.h" namespace cc { @@ -42,7 +43,7 @@ class CC_EXPORT LayerListIterator { // `current_layer` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - Layer* current_layer_; + RAW_PTR_EXCLUSION Layer* current_layer_; std::vector<size_t> list_indices_; }; @@ -67,7 +68,7 @@ class CC_EXPORT LayerListConstIterator { const Layer* operator*() const { return current_layer_; } private: - const Layer* current_layer_; + raw_ptr<const Layer> current_layer_; std::vector<size_t> list_indices_; }; diff --git a/chromium/cc/layers/layer_perftest.cc b/chromium/cc/layers/layer_perftest.cc index 4c419ecb509..dba359c1b9d 100644 --- a/chromium/cc/layers/layer_perftest.cc +++ b/chromium/cc/layers/layer_perftest.cc @@ -125,7 +125,7 @@ TEST_F(LayerPerfTest, ImplPushPropertiesTo) { std::unique_ptr<LayerImpl> impl_layer = LayerImpl::Create(host_impl_.active_tree(), 2); - SkColor background_color = SK_ColorRED; + SkColor4f background_color = SkColors::kRed; gfx::Size bounds(1000, 1000); bool draws_content = true; bool contents_opaque = true; @@ -142,7 +142,7 @@ TEST_F(LayerPerfTest, ImplPushPropertiesTo) { test_layer->PushPropertiesTo(impl_layer.get()); background_color = - background_color == SK_ColorRED ? SK_ColorGREEN : SK_ColorRED; + background_color == SkColors::kRed ? SkColors::kGreen : SkColors::kRed; bounds = bounds == gfx::Size(1000, 1000) ? gfx::Size(500, 500) : gfx::Size(1000, 1000); draws_content = !draws_content; diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc index 372a57aab19..e822609d136 100644 --- a/chromium/cc/layers/layer_unittest.cc +++ b/chromium/cc/layers/layer_unittest.cc @@ -87,6 +87,21 @@ using ::testing::_; EXPECT_FALSE(child->subtree_property_changed()); \ EXPECT_FALSE(grand_child->subtree_property_changed()); +// TODO(https://crbug.com/1330728): tests should be cleaned up to eliminate +// mixing of EXPECT_CALL with calls to the mock functions. This method +// should be deduped with EXPECT_SET_NEEDS_COMMIT as part of this cleanup. +#define EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(code_to_test) \ + do { \ + code_to_test; \ + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); \ + } while (false) + +#define EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED(code_to_test) \ + do { \ + code_to_test; \ + EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset()); \ + } while (false) + namespace cc { namespace { @@ -110,9 +125,18 @@ class MockLayerTreeHost : public LayerTreeHost { return thread_unsafe_commit_state(); } - MOCK_METHOD0(SetNeedsCommit, void()); - MOCK_METHOD0(SetNeedsUpdateLayers, void()); - MOCK_METHOD0(SetNeedsFullTreeSync, void()); + MOCK_METHOD(void, SetNeedsUpdateLayers, (), (override)); + MOCK_METHOD(void, SetNeedsFullTreeSync, (), (override)); + + void SetNeedsCommit() override { needs_commit_ = true; } + bool GetNeedsCommitAndReset() { + const bool out = needs_commit_; + needs_commit_ = false; + return out; + } + + private: + bool needs_commit_ = false; }; bool LayerNeedsDisplay(Layer* layer) { @@ -259,11 +283,7 @@ TEST_F(LayerTest, BasicCreateAndDestroy) { scoped_refptr<Layer> test_layer = Layer::Create(); ASSERT_TRUE(test_layer.get()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); test_layer->SetLayerTreeHost(layer_tree_host_.get()); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); test_layer->SetLayerTreeHost(nullptr); } @@ -283,21 +303,22 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { top->AddChild(child); top->AddChild(child2); child->AddChild(grand_child); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); + // To force a transform node for |top|. gfx::Transform top_transform; top_transform.Scale3d(1, 2, 3); top->SetTransform(top_transform); child->SetForceRenderSurfaceForTesting(true); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); // Resizing without a mask layer or masks_to_bounds, should only require a // regular commit. Note that a layer and its mask should match sizes, but // the mask isn't in the tree yet, so won't need its own commit. gfx::Size arbitrary_size = gfx::Size(1, 2); - EXPECT_SET_NEEDS_COMMIT(1, top->SetBounds(arbitrary_size)); - EXPECT_SET_NEEDS_COMMIT(0, mask_layer1->SetBounds(arbitrary_size)); - EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(top->SetBounds(arbitrary_size)); + EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED( + mask_layer1->SetBounds(arbitrary_size)); + EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()); layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMaskLayer(mask_layer1)); @@ -335,11 +356,11 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { // Once there is a mask layer, resizes require subtree properties to update. arbitrary_size = gfx::Size(11, 22); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMasksToBounds(true)); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, @@ -351,9 +372,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { grand_child->PushPropertiesTo(grand_child_impl.get(), *commit_state, unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetContentsOpaque(true)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -365,8 +387,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(true)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -378,8 +400,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(false)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -391,9 +413,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); top->SetRoundedCorner({1, 2, 3, 4}); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetIsFastRoundedCorner(true)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -405,8 +428,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetHideLayerAndSubtree(true)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -418,8 +441,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBlendMode(arbitrary_blend_mode)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -434,9 +457,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { // Should be a different size than previous call, to ensure it marks tree // changed. arbitrary_size = gfx::Size(111, 222); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -450,8 +474,8 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { FilterOperations arbitrary_filters; arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetFilters(arbitrary_filters)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -463,7 +487,6 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( top->SetBackdropFilters(arbitrary_filters)); @@ -476,9 +499,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { grand_child->PushPropertiesTo(grand_child_impl.get(), *commit_state, unsafe_state)); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); top->SetPosition(arbitrary_point_f); TransformNode* node = layer_tree_host_->property_trees()->transform_tree_mutable().Node( @@ -496,12 +519,13 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { layer_tree_host_->property_trees()->ResetAllChangeTracking()); layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); EXPECT_FALSE(node->transform_changed); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); child->SetPosition(arbitrary_point_f); node = layer_tree_host_->property_trees()->transform_tree_mutable().Node( child->transform_tree_index()); EXPECT_TRUE(node->transform_changed); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -516,11 +540,11 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { EXPECT_FALSE(node->transform_changed); gfx::Point3F arbitrary_point_3f = gfx::Point3F(0.125f, 0.25f, 0.f); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); top->SetTransformOrigin(arbitrary_point_3f); node = layer_tree_host_->property_trees()->transform_tree_mutable().Node( top->transform_tree_index()); EXPECT_TRUE(node->transform_changed); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr, /*has_updates=*/true); @@ -535,11 +559,11 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { gfx::Transform arbitrary_transform; arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); top->SetTransform(arbitrary_transform); node = layer_tree_host_->property_trees()->transform_tree_mutable().Node( top->transform_tree_index()); EXPECT_TRUE(node->transform_changed); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); } TEST_F(LayerTest, AddAndRemoveChild) { @@ -787,8 +811,8 @@ TEST_F(LayerTest, ReplaceChildWithNewChild) { EXPECT_FALSE(child4->parent()); - EXPECT_SET_NEEDS_FULL_TREE_SYNC( - AtLeast(1), parent_->ReplaceChild(child2_.get(), child4)); + EXPECT_SET_NEEDS_FULL_TREE_SYNC(AtLeast(1), + parent_->ReplaceChild(child2_.get(), child4)); EXPECT_FALSE(LayerNeedsDisplay(parent_.get())); EXPECT_FALSE(LayerNeedsDisplay(child1_.get())); EXPECT_FALSE(LayerNeedsDisplay(child2_.get())); @@ -815,8 +839,8 @@ TEST_F(LayerTest, ReplaceChildWithNewChildThatHasOtherParent) { EXPECT_EQ(child4, test_layer->children()[0]); EXPECT_EQ(test_layer.get(), child4->parent()); - EXPECT_SET_NEEDS_FULL_TREE_SYNC( - AtLeast(1), parent_->ReplaceChild(child2_.get(), child4)); + EXPECT_SET_NEEDS_FULL_TREE_SYNC(AtLeast(1), + parent_->ReplaceChild(child2_.get(), child4)); ASSERT_EQ(3U, parent_->children().size()); EXPECT_EQ(child1_, parent_->children()[0]); @@ -833,10 +857,8 @@ TEST_F(LayerTest, ReplaceChildWithNewChildThatHasOtherParent) { TEST_F(LayerTest, ReplaceChildWithSameChild) { CreateSimpleTestTree(); - // SetNeedsFullTreeSync / SetNeedsCommit should not be called because its the - // same child. - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); - EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(0); + // SetNeedsFullTreeSync / SetNeedsCommit should not be called because its + // the same child. parent_->ReplaceChild(child2_.get(), child2_); VerifyTestTreeInitialState(); @@ -886,7 +908,7 @@ TEST_F(LayerTest, GetRootLayerAfterTreeManipulations) { EXPECT_EQ(parent_.get(), child1_->RootLayer()); EXPECT_EQ(parent_.get(), child2_->RootLayer()); EXPECT_EQ(parent_.get(), child3_->RootLayer()); - EXPECT_EQ(child4.get(), child4->RootLayer()); + EXPECT_EQ(child4.get(), child4->RootLayer()); EXPECT_EQ(parent_.get(), grand_child1_->RootLayer()); EXPECT_EQ(parent_.get(), grand_child2_->RootLayer()); EXPECT_EQ(parent_.get(), grand_child3_->RootLayer()); @@ -917,8 +939,8 @@ TEST_F(LayerTest, GetRootLayerAfterTreeManipulations) { child2_->ReplaceChild(grand_child3_.get(), child1_); - // |grand_child3| gets orphaned and the child1 subtree gets planted back into - // the tree under child2. + // |grand_child3| gets orphaned and the child1 subtree gets planted back + // into the tree under child2. EXPECT_EQ(parent_.get(), parent_->RootLayer()); EXPECT_EQ(parent_.get(), child1_->RootLayer()); EXPECT_EQ(parent_.get(), child2_->RootLayer()); @@ -938,7 +960,7 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) { scoped_refptr<Layer> test_layer = Layer::Create(); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetIsDrawable(true)); gfx::Size test_bounds = gfx::Size(501, 508); @@ -948,9 +970,9 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) { // Before anything, test_layer should not be dirty. EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); - // This is just initialization, but SetNeedsCommit behavior is verified anyway - // to avoid warnings. - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBounds(test_bounds)); + // This is just initialization, but SetNeedsCommit behavior is verified + // anyway to avoid warnings. + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetBounds(test_bounds)); EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); // The real test begins here. @@ -972,12 +994,13 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) { // Case 3: SetNeedsDisplay() with an empty rect. EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); - EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetNeedsDisplayRect(gfx::Rect())); + EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED( + test_layer->SetNeedsDisplayRect(gfx::Rect())); EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); SimulateCommitForLayer(test_layer.get()); // Case 4: SetNeedsDisplay() with a non-drawable layer - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(false)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetIsDrawable(false)); SimulateCommitForLayer(test_layer.get()); EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); EXPECT_SET_NEEDS_UPDATE(0, test_layer->SetNeedsDisplayRect(dirty_rect)); @@ -988,7 +1011,7 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { scoped_refptr<Layer> test_layer = Layer::Create(); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetIsDrawable(true)); FakeContentLayerClient client; scoped_refptr<PictureLayer> mask_layer1 = PictureLayer::Create(&client); @@ -999,37 +1022,50 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { // Next, test properties that should call SetNeedsCommit (but not // SetNeedsDisplay). All properties need to be set to new values in order for // SetNeedsCommit to be called. - EXPECT_SET_NEEDS_COMMIT( - 1, test_layer->SetTransformOrigin(gfx::Point3F(1.23f, 4.56f, 0.f))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetClipRect(gfx::Rect(1, 2, 3, 4))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetRoundedCorner({1, 2, 3, 4})); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsFastRoundedCorner(true)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendMode(SkBlendMode::kHue)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetContentsOpaque(true)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetTransformOrigin(gfx::Point3F(1.23f, 4.56f, 0.f))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetBackgroundColor(SkColors::kLtGray)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetMasksToBounds(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetClipRect(gfx::Rect(1, 2, 3, 4))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetRoundedCorner({1, 2, 3, 4})); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetIsFastRoundedCorner(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetOpacity(0.5f)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetBlendMode(SkBlendMode::kHue)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetContentsOpaque(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetPosition(gfx::PointF(4.f, 9.f))); // We can use any layer pointer here since we aren't syncing for real. - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollable(gfx::Size(1, 1))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset(gfx::PointF(10, 10))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion( - Region(gfx::Rect(1, 1, 2, 2)))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform( - gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetScrollable(gfx::Size(1, 1))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetUserScrollable(true, false)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetScrollOffset(gfx::PointF(10, 10))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetNonFastScrollableRegion(Region(gfx::Rect(1, 1, 2, 2)))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetTransform(gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))); TouchActionRegion touch_action_region; touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10)); - EXPECT_SET_NEEDS_COMMIT( - 1, test_layer->SetTouchActionRegion(std::move(touch_action_region))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurfaceForTesting(true)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetElementId(ElementId(2))); - - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetTouchActionRegion(std::move(touch_action_region))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetForceRenderSurfaceForTesting(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetHideLayerAndSubtree(true)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetElementId(ElementId(2))); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetCaptureBounds(viz::RegionCaptureBounds( + base::flat_map<viz::RegionCaptureCropId, gfx::Rect>{ + {viz::RegionCaptureCropId(123u, 456u), + gfx::Rect(0, 0, 640, 480)}}))); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetMaskLayer(mask_layer1)); - - // The above tests should not have caused a change to the needs_display flag. + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); + // The above tests should not have caused a change to the needs_display + // flag. EXPECT_FALSE(LayerNeedsDisplay(test_layer.get())); // As layers are removed from the tree, they will cause a tree sync. @@ -1050,8 +1086,8 @@ TEST_F(LayerTest, PushPropertiesAccumulatesUpdateRect) { CommitAndPushProperties(test_layer.get(), impl_layer_ptr); EXPECT_EQ(gfx::Rect(0, 0, 5, 5), impl_layer_ptr->update_rect()); - // The LayerImpl's update_rect() should be accumulated here, since we did not - // do anything to clear it. + // The LayerImpl's update_rect() should be accumulated here, since we did + // not do anything to clear it. test_layer->SetNeedsDisplayRect(gfx::Rect(10, 10, 5, 5)); CommitAndPushProperties(test_layer.get(), impl_layer_ptr); EXPECT_EQ(gfx::Rect(0, 0, 15, 15), impl_layer_ptr->update_rect()); @@ -1074,7 +1110,7 @@ TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForTransform) { gfx::Transform transform; transform.Rotate(45.0); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetTransform(transform)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); @@ -1094,7 +1130,8 @@ TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForRoundCorner) { EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetRoundedCorner({1, 2, 3, 4})); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED( + test_layer->SetRoundedCorner({1, 2, 3, 4})); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); @@ -1113,7 +1150,7 @@ TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForOpacity) { EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); + EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(test_layer->SetOpacity(0.5f)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); @@ -1182,8 +1219,8 @@ TEST_F(LayerLayerTreeHostTest, EnteringTree) { FakeContentLayerClient client; scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client); - // Set up a detached tree of layers. The host pointer should be nil for these - // layers. + // Set up a detached tree of layers. The host pointer should be nil for + // these layers. parent->AddChild(child); child->SetMaskLayer(mask); @@ -1255,8 +1292,9 @@ TEST_F(LayerLayerTreeHostTest, ChangeHost) { AssertLayerTreeHostMatchesForSubtree(parent.get(), first_layer_tree_host.get()); - // Now re-root the tree to a new host (simulating what we do on a context lost - // event). This should update the host pointers for all layers in the tree. + // Now re-root the tree to a new host (simulating what we do on a context + // lost event). This should update the host pointers for all layers in the + // tree. auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); std::unique_ptr<LayerTreeHost> second_layer_tree_host = factory.Create(animation_host2.get()); @@ -1289,8 +1327,8 @@ TEST_F(LayerLayerTreeHostTest, ChangeHostInSubtree) { AssertLayerTreeHostMatchesForSubtree(first_parent.get(), first_layer_tree_host.get()); - // Now reparent the subtree starting at second_child to a layer in a different - // tree. + // Now reparent the subtree starting at second_child to a layer in a + // different tree. auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); std::unique_ptr<LayerTreeHost> second_layer_tree_host = factory.Create(animation_host2.get()); @@ -1327,7 +1365,8 @@ TEST_F(LayerLayerTreeHostTest, ReplaceMaskLayer) { AssertLayerTreeHostMatchesForSubtree(parent.get(), layer_tree_host.get()); - // Replacing the mask should clear out the old mask's subtree's host pointers. + // Replacing the mask should clear out the old mask's subtree's host + // pointers. parent->SetMaskLayer(mask_replacement); EXPECT_EQ(nullptr, mask->layer_tree_host()); EXPECT_EQ(nullptr, mask_child->layer_tree_host()); @@ -1360,23 +1399,17 @@ TEST_F(LayerTest, SafeOpaqueBackgroundColor) { for (int layer_opaque = 0; layer_opaque < 2; ++layer_opaque) { for (int host_opaque = 0; host_opaque < 2; ++host_opaque) { layer->SetContentsOpaque(!!contents_opaque); - layer->SetBackgroundColor(layer_opaque ? SK_ColorRED - : SK_ColorTRANSPARENT); + layer->SetBackgroundColor(layer_opaque ? SkColors::kRed + : SkColors::kTransparent); layer_tree_host->set_background_color( host_opaque ? SK_ColorRED : SK_ColorTRANSPARENT); layer_tree_host->property_trees()->set_needs_rebuild(true); layer_tree_host->BuildPropertyTreesForTesting(); - SkColor safe_color = layer->SafeOpaqueBackgroundColor(); - if (contents_opaque) { - EXPECT_EQ(SkColorGetA(safe_color), 255u) - << "Flags: " << contents_opaque << ", " << layer_opaque << ", " - << host_opaque << "\n"; - } else { - EXPECT_NE(SkColorGetA(safe_color), 255u) - << "Flags: " << contents_opaque << ", " << layer_opaque << ", " - << host_opaque << "\n"; - } + EXPECT_EQ(contents_opaque, + layer->SafeOpaqueBackgroundColor().isOpaque()) + << "Flags: " << contents_opaque << ", " << layer_opaque << ", " + << host_opaque << "\n"; } } } @@ -1433,7 +1466,6 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) { LayerImpl::Create(host_impl_.active_tree(), 1); EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(root_layer)); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(5); // A layer that draws content should be hit testable. root_layer->SetIsDrawable(true); @@ -1441,6 +1473,7 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) { CommitAndPushProperties(root_layer.get(), impl_layer.get()); EXPECT_TRUE(impl_layer->draws_content()); EXPECT_TRUE(impl_layer->HitTestable()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); // A layer that does not draw content and does not hit test without drawing // content should not be hit testable. @@ -1449,6 +1482,7 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) { CommitAndPushProperties(root_layer.get(), impl_layer.get()); EXPECT_FALSE(impl_layer->draws_content()); EXPECT_FALSE(impl_layer->HitTestable()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); // |SetHitTestableWithoutDrawsContent| should cause a layer to become hit // testable even though it does not draw content. @@ -1456,6 +1490,7 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) { CommitAndPushProperties(root_layer.get(), impl_layer.get()); EXPECT_FALSE(impl_layer->draws_content()); EXPECT_TRUE(impl_layer->HitTestable()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); } void ReceiveCopyOutputResult(int* result_count, @@ -1581,12 +1616,12 @@ TEST_F(LayerTest, AnimationSchedulesLayerUpdate) { EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer)); auto element_id = layer->element_id(); - EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); + EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()); layer_tree_host_->SetElementOpacityMutated(element_id, ElementListType::ACTIVE, 0.5f); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1); + EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()); gfx::Transform transform; transform.Rotate(45.0); layer_tree_host_->SetElementTransformMutated( @@ -1609,15 +1644,12 @@ TEST_F(LayerTest, ElementIdIsPushed) { EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); - test_layer->SetElementId(ElementId(2)); - EXPECT_FALSE(impl_layer->element_id()); CommitAndPushProperties(test_layer.get(), impl_layer.get()); - EXPECT_EQ(ElementId(2), impl_layer->element_id()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); } TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) { @@ -1627,7 +1659,6 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) { // Expect additional calls due to has-animation check and initialization // of keyframes. - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(3); scoped_refptr<AnimationTimeline> timeline = AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); animation_host_->AddAnimationTimeline(timeline); @@ -1635,11 +1666,17 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) { AddOpacityTransitionToElementWithAnimation(element_id, timeline, 10.0, 1.f, 0.f, false); EXPECT_TRUE(animation_host_->IsElementAnimating(element_id)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); test_layer->SetLayerTreeHost(layer_tree_host_.get()); // Layer should now be registered by element id. EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); + + // We're expected to remove the animations before calling + // SetLayerTreeHost(nullptr). + animation_host_->RemoveAnimationTimeline(timeline); test_layer->SetLayerTreeHost(nullptr); // Layer should have been un-registered. @@ -1650,7 +1687,6 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) { // compositor is expensive and updated counts can wait until the next // commit to be pushed. See https://crbug.com/1083244. TEST_F(LayerTest, PushAnimationCountsLazily) { - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0); animation_host_->SetAnimationCounts(0); animation_host_->SetCurrentFrameHadRaf(true); animation_host_->SetNextFrameHasPendingRaf(true); @@ -1662,19 +1698,20 @@ TEST_F(LayerTest, PushAnimationCountsLazily) { *layer_tree_host_->property_trees()); EXPECT_TRUE(host_impl_.animation_host()->CurrentFrameHadRAF()); EXPECT_TRUE(host_impl_.animation_host()->HasSmilAnimation()); + EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset()); } TEST_F(LayerTest, SetElementIdNotUsingLayerLists) { scoped_refptr<Layer> test_layer = Layer::Create(); test_layer->SetLayerTreeHost(layer_tree_host_.get()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2); ElementId element_id = ElementId(2); EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id)); test_layer->SetElementId(element_id); // Layer should now be registered by element id. EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id)); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); ElementId other_element_id = ElementId(3); test_layer->SetElementId(other_element_id); @@ -1684,6 +1721,7 @@ TEST_F(LayerTest, SetElementIdNotUsingLayerLists) { EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(other_element_id)); test_layer->SetLayerTreeHost(nullptr); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); } // Verifies that when mirror count of the layer is incremented or decremented, @@ -1703,7 +1741,8 @@ TEST_F(LayerTest, UpdateMirrorCount) { EXPECT_EQ(0u, layer_tree_host_->GetPendingCommitState() ->layers_that_should_push_properties.size()); - // Incrementing mirror count from zero should trigger property trees rebuild. + // Incrementing mirror count from zero should trigger property trees + // rebuild. test_layer->IncrementMirrorCount(); EXPECT_EQ(1, test_layer->mirror_count()); EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild()); @@ -1747,6 +1786,64 @@ TEST_F(LayerTest, UpdateMirrorCount) { test_layer->SetLayerTreeHost(nullptr); } +TEST_F(LayerTest, UpdatingCaptureBounds) { + static const viz::RegionCaptureBounds kEmptyBounds; + static const viz::RegionCaptureBounds kPopulatedBounds( + base::flat_map<viz::RegionCaptureCropId, gfx::Rect>{ + {viz::RegionCaptureCropId(123u, 456u), gfx::Rect(0, 0, 640, 480)}}); + static const viz::RegionCaptureBounds kUpdatedBounds( + base::flat_map<viz::RegionCaptureCropId, gfx::Rect>{ + {viz::RegionCaptureCropId(123u, 456u), gfx::Rect(0, 0, 1280, 720)}}); + + // We don't track full tree syncs in this test. + EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); + + scoped_refptr<Layer> layer = Layer::Create(); + layer_tree_host_->SetRootLayer(layer); + + // Clear the updates caused by setting a new root layer. + layer->ClearSubtreePropertyChangedForTesting(); + layer_tree_host_->property_trees()->set_needs_rebuild(false); + + // An empty bounds when none is currently set should not cause an update. + layer->SetCaptureBounds(kEmptyBounds); + EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild()); + EXPECT_FALSE(layer->subtree_property_changed()); + EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset()); + + // Setting to a new bounds should cause an update. + layer->SetCaptureBounds(kPopulatedBounds); + EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild()); + EXPECT_TRUE(layer->subtree_property_changed()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); + + // Reset properties. + layer->ClearSubtreePropertyChangedForTesting(); + layer_tree_host_->property_trees()->set_needs_rebuild(false); + + // Setting to the same bounds should not, however. + layer->SetCaptureBounds(kPopulatedBounds); + EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild()); + EXPECT_FALSE(layer->subtree_property_changed()); + EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset()); + + // Switching to a differently valued bounds should cause an update. + layer->SetCaptureBounds(kUpdatedBounds); + EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild()); + EXPECT_TRUE(layer->subtree_property_changed()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); + + // Reset properties. + layer->ClearSubtreePropertyChangedForTesting(); + layer_tree_host_->property_trees()->set_needs_rebuild(false); + + // Finally, setting to empty should cause an update. + layer->SetCaptureBounds(kEmptyBounds); + EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild()); + EXPECT_TRUE(layer->subtree_property_changed()); + EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); +} + TEST_F(LayerTest, UpdatingClipRect) { const gfx::Size kRootSize(200, 200); const gfx::Vector2dF kParentOffset(10.f, 20.f); @@ -1765,7 +1862,6 @@ TEST_F(LayerTest, UpdatingClipRect) { scoped_refptr<Layer> clipped_4 = Layer::Create(); EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); layer_tree_host_->SetRootLayer(root); root->AddChild(parent); parent->AddChild(clipped_1); @@ -1807,9 +1903,9 @@ TEST_F(LayerTest, UpdatingClipRect) { EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_3->clip); EXPECT_EQ(gfx::RectF(kClipRect) + kParentOffset, node_4->clip); - // The following layer properties should result in the layer being clipped to - // its bounds along with being clipped by the clip rect. Check if the final - // rect on the clip node is set correctly. + // The following layer properties should result in the layer being clipped + // to its bounds along with being clipped by the clip rect. Check if the + // final rect on the clip node is set correctly. // Setting clip to layer bounds. clipped_1->SetMasksToBounds(true); @@ -1871,7 +1967,6 @@ TEST_F(LayerTest, UpdatingRoundedCorners) { scoped_refptr<Layer> layer_5 = Layer::Create(); EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1)); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1)); layer_tree_host_->SetRootLayer(root); root->AddChild(layer_1); root->AddChild(layer_2); diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index b8d830dca49..39e68be28b6 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -230,9 +230,10 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, Occlusion occlusion = draw_properties().occlusion_in_content_space; EffectNode* effect_node = GetEffectTree().Node(effect_tree_index()); + // TODO(crbug/1308932): Remove FromColor and make all SkColor4f. SolidColorLayerImpl::AppendSolidQuads( render_pass, occlusion, shared_quad_state, scaled_visible_layer_rect, - raster_source_->GetSolidColor(), + SkColor4f::FromColor(raster_source_->GetSolidColor()), !layer_tree_impl()->settings().enable_edge_anti_aliasing, effect_node->blend_mode, append_quads_data); return; @@ -366,7 +367,7 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, shared_quad_state->visible_quad_layer_rect, ideal_contents_scale_key()); iter; ++iter) { - SkColor color; + SkColor4f color; float width; if (*iter && iter->draw_info().IsReadyToDraw()) { TileDrawInfo::Mode mode = iter->draw_info().mode(); @@ -399,23 +400,24 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, gfx::Rect geometry_rect = iter.geometry_rect(); geometry_rect.Offset(quad_offset); gfx::Rect visible_geometry_rect = geometry_rect; - debug_border_quad->SetNew(shared_quad_state, - geometry_rect, - visible_geometry_rect, - color, + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + debug_border_quad->SetNew(shared_quad_state, geometry_rect, + visible_geometry_rect, color.toSkColor(), width); } } if (layer_tree_impl()->debug_state().highlight_non_lcd_text_layers) { - SkColor color = + // TODO(crbug/1308932): Remove all instances of toSkColor below and make all + // SkColor4f. + SkColor4f color = DebugColors::NonLCDTextHighlightColor(lcd_text_disallowed_reason()); - if (color != SK_ColorTRANSPARENT && + if (color != SkColors::kTransparent && GetRasterSource()->GetDisplayItemList()->AreaOfDrawText( gfx::Rect(bounds()))) { render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>()->SetNew( - shared_quad_state, debug_border_rect, debug_border_rect, color, - append_quads_data); + shared_quad_state, debug_border_rect, debug_border_rect, + color.toSkColor(), append_quads_data); } } @@ -513,15 +515,16 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, if (!has_draw_quad) { // Checkerboard. - SkColor color = safe_opaque_background_color(); + SkColor4f color = safe_opaque_background_color(); if (ShowDebugBorders(DebugBorderType::LAYER)) { // Fill the whole tile with the missing tile color. color = DebugColors::DefaultCheckerboardColor(); } auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. quad->SetNew(shared_quad_state, offset_geometry_rect, - offset_visible_geometry_rect, color, false); + offset_visible_geometry_rect, color.toSkColor(), false); ValidateQuadResources(quad); if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) { @@ -840,10 +843,11 @@ void PictureLayerImpl::UpdateCanUseLCDText( ComputeLCDTextDisallowedReason(raster_translation_aligns_pixels); } -bool PictureLayerImpl::HasWillChangeTransformHint() const { +bool PictureLayerImpl::AffectedByWillChangeTransformHint() const { TransformNode* transform_node = GetTransformTree().Node(transform_tree_index()); - return transform_node && transform_node->will_change_transform; + return transform_node && + transform_node->node_or_ancestors_will_change_transform; } LCDTextDisallowedReason PictureLayerImpl::ComputeLCDTextDisallowedReason( @@ -859,7 +863,7 @@ LCDTextDisallowedReason PictureLayerImpl::ComputeLCDTextDisallowedReason( if (!layer_tree_impl()->settings().can_use_lcd_text) return LCDTextDisallowedReason::kSetting; if (!contents_opaque_for_text()) { - if (SkColorGetA(background_color()) != SK_AlphaOPAQUE) + if (!background_color().isOpaque()) return LCDTextDisallowedReason::kBackgroundColorNotOpaque; return LCDTextDisallowedReason::kContentsNotOpaque; } @@ -1224,16 +1228,13 @@ void PictureLayerImpl::RemoveAllTilings() { bool PictureLayerImpl::CanRecreateHighResTilingForLCDTextAndRasterTransform( const PictureLayerTiling& high_res) const { - // This is for the sync tree only to avoid flickering. - if (!layer_tree_impl()->IsSyncTree()) - return false; // We can recreate the tiling if we would invalidate all of its tiles. if (high_res.may_contain_low_resolution_tiles()) return true; // Keep the non-ideal raster translation unchanged for transform animations // to avoid re-rasterization during animation. if (draw_properties().screen_space_transform_is_animating || - HasWillChangeTransformHint()) + AffectedByWillChangeTransformHint()) return false; // Also avoid re-rasterization during pinch-zoom. if (layer_tree_impl()->PinchGestureActive()) @@ -1243,6 +1244,11 @@ bool PictureLayerImpl::CanRecreateHighResTilingForLCDTextAndRasterTransform( if (lcd_text_disallowed_reason_ == LCDTextDisallowedReason::kNoText && high_res.raster_transform().scale() == raster_contents_scale_) return false; + // If ReadyToActivate() is already scheduled, recreating tiling should be + // delayed until the activation is executed. Otherwise the tiles in viewport + // will be deleted. + if (layer_tree_impl()->IsSyncTree() && layer_tree_impl()->IsReadyToActivate()) + return false; return true; } @@ -1261,12 +1267,28 @@ void PictureLayerImpl::UpdateTilingsForRasterScaleAndTranslation( high_res->raster_transform().translation() != raster_translation; bool can_use_lcd_text_changed = high_res->can_use_lcd_text() != can_use_lcd_text(); + bool can_recreate_highres_tiling = + CanRecreateHighResTilingForLCDTextAndRasterTransform(*high_res); + // Only for the sync tree to avoid flickering. bool should_recreate_high_res = (raster_transform_is_not_ideal || can_use_lcd_text_changed) && - CanRecreateHighResTilingForLCDTextAndRasterTransform(*high_res); + layer_tree_impl()->IsSyncTree() && can_recreate_highres_tiling; + // Only request an invalidation if we don't already have a pending tree. + bool can_request_invalidation_for_high_res = + (raster_transform_is_not_ideal || can_use_lcd_text_changed) && + !layer_tree_impl()->settings().commit_to_active_tree && + layer_tree_impl()->IsActiveTree() && can_recreate_highres_tiling && + !layer_tree_impl()->HasPendingTree(); + if (should_recreate_high_res) { tilings_->Remove(high_res); high_res = nullptr; + } else if (can_request_invalidation_for_high_res) { + // Anytime a condition which flips whether we can recreate the tiling + // changes, we'll get a call to UpdateDrawProperties. We check whether we + // could recreate the tiling when this runs on the active tree to trigger + // an impl-side invalidation (if needed). + layer_tree_impl()->RequestImplSideInvalidationForRerasterTiling(); } else if (!has_adjusted_raster_scale) { // Nothing changed, no need to update tilings. DCHECK_EQ(HIGH_RESOLUTION, high_res->resolution()); @@ -1353,7 +1375,7 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const { // will-change: transform hint to preserve maximum resolution tiles // needed. if (draw_properties().screen_space_transform_is_animating || - !HasWillChangeTransformHint()) + !AffectedByWillChangeTransformHint()) return true; } @@ -1418,7 +1440,7 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const { // Don't update will-change: transform layers if the raster contents scale is // bigger than the minimum scale. - if (HasWillChangeTransformHint()) { + if (AffectedByWillChangeTransformHint()) { float min_raster_scale = MinimumRasterContentsScaleForWillChangeTransform(); if (raster_contents_scale_.x() >= min_raster_scale && raster_contents_scale_.y() >= min_raster_scale) @@ -1525,7 +1547,7 @@ void PictureLayerImpl::RecalculateRasterScales() { if (draw_properties().screen_space_transform_is_animating) AdjustRasterScaleForTransformAnimation(preserved_raster_contents_scale); - if (HasWillChangeTransformHint()) { + if (AffectedByWillChangeTransformHint()) { float min_scale = MinimumRasterContentsScaleForWillChangeTransform(); raster_contents_scale_.SetToMax(gfx::Vector2dF(min_scale, min_scale)); } @@ -1571,7 +1593,7 @@ void PictureLayerImpl::AdjustRasterScaleForTransformAnimation( raster_contents_scale_.SetToMax( gfx::Vector2dF(maximum_animation_scale, maximum_animation_scale)); - if (HasWillChangeTransformHint()) { + if (AffectedByWillChangeTransformHint()) { // If we have a will-change: transform hint, do not shrink the content // raster scale, otherwise we will end up throwing away larger tiles we may // need again. @@ -1637,7 +1659,7 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer( float PictureLayerImpl::MinimumRasterContentsScaleForWillChangeTransform() const { - DCHECK(HasWillChangeTransformHint()); + DCHECK(AffectedByWillChangeTransformHint()); float native_scale = ideal_device_scale_ * ideal_page_scale_; float ideal_scale = ideal_contents_scale_key(); // Clamp will-change: transform layers to be at least the native scale, @@ -1810,7 +1832,7 @@ void PictureLayerImpl::UpdateIdealScales() { ideal_contents_scale_ = GetIdealContentsScale(); if (layer_tree_impl()->PageScaleTransformNode()) { - DCHECK(!layer_tree_impl()->settings().is_layer_tree_for_subframe); + DCHECK(layer_tree_impl()->settings().is_for_scalable_page); ideal_page_scale_ = IsAffectedByPageScale() ? layer_tree_impl()->current_page_scale_factor() : 1.f; @@ -1819,16 +1841,16 @@ void PictureLayerImpl::UpdateIdealScales() { // This layer may be in a layer tree embedded in a hierarchy that has its own // page scale factor. We represent that here as 'external_page_scale_factor', // a value that affects raster scale in the same way that page_scale_factor - // does, but doesn't affect any geometry calculations. In a normal main frame - // or OOPIF, only one of current or external page scale factor is ever used - // but not both. The only exception to this is a main frame in a portal. It - // may have a current_page_scale_factor (e.g. due to a viewport <meta> tag) - // as well as an external_page_scale_factor coming from the page scale of its - // embedder page. + // does, but doesn't affect any geometry calculations. In a normal main frame, + // fenced frame, or OOPIF, only one of current or external page scale factor + // is ever used but not both. The only exception to this is a main frame in a + // portal or a guest view. In these cases we may have a + // current_page_scale_factor (e.g. due to a viewport <meta> tag) as well as an + // external_page_scale_factor coming from the page scale of its embedder page. float external_page_scale_factor = layer_tree_impl() ? layer_tree_impl()->external_page_scale_factor() : 1.f; DCHECK(!layer_tree_impl() || - !layer_tree_impl()->settings().is_layer_tree_for_subframe || + layer_tree_impl()->settings().is_for_scalable_page || external_page_scale_factor == 1.f || layer_tree_impl()->current_page_scale_factor() == 1.f); ideal_page_scale_ *= external_page_scale_factor; @@ -1842,9 +1864,8 @@ void PictureLayerImpl::UpdateIdealScales() { ideal_contents_scale_.y() / ideal_page_scale_}; } -void PictureLayerImpl::GetDebugBorderProperties( - SkColor* color, - float* width) const { +void PictureLayerImpl::GetDebugBorderProperties(SkColor4f* color, + float* width) const { float device_scale_factor = layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1; diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h index b25dfa0a0fc..23ca1f2c635 100644 --- a/chromium/cc/layers/picture_layer_impl.h +++ b/chromium/cc/layers/picture_layer_impl.h @@ -214,7 +214,7 @@ class CC_EXPORT PictureLayerImpl void SanityCheckTilingState() const; - void GetDebugBorderProperties(SkColor* color, float* width) const override; + void GetDebugBorderProperties(SkColor4f* color, float* width) const override; void GetAllPrioritizedTilesForTracing( std::vector<PrioritizedTile>* prioritized_tiles) const override; void AsValueInto(base::trace_event::TracedValue* dict) const override; @@ -236,10 +236,9 @@ class CC_EXPORT PictureLayerImpl bool raster_translation_aligns_pixels) const; void UpdateCanUseLCDText(bool raster_translation_aligns_pixels); - // TODO(crbug.com/1114504): For now this checks the immediate transform node - // only. The callers may actually want to know if this layer or ancestor has - // will change transform. - bool HasWillChangeTransformHint() const; + // Whether the transform node for this layer, or any ancestor transform + // node, has a will-change hint for one of the transform properties. + bool AffectedByWillChangeTransformHint() const; raw_ptr<PictureLayerImpl> twin_layer_ = nullptr; diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc index 53ff0342e61..ba9a96637b4 100644 --- a/chromium/cc/layers/picture_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_layer_impl_unittest.cc @@ -915,7 +915,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) { float page_scale = 1.f; SetupDefaultTrees(layer_bounds); - GetTransformNode(active_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); EXPECT_FLOAT_EQ(2u, active_layer()->tilings()->num_tilings()); EXPECT_FLOAT_EQ( 1.f, active_layer()->tilings()->tiling_at(0)->contents_scale_key()); @@ -2073,7 +2073,7 @@ TEST_F(LegacySWPictureLayerImplTest, SetInitialDeviceScaleFactor(2.f); SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region()); - GetTransformNode(active_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); // One ideal tile exists, this will get used when drawing. std::vector<Tile*> ideal_tiles; @@ -3103,8 +3103,8 @@ TEST_F(LegacySWPictureLayerImplTest, EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f); - GetTransformNode(active_layer())->will_change_transform = true; - GetTransformNode(pending_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); + SetWillChangeTransform(pending_layer(), true); // Starting an animation should cause tiling resolution to get set to the // maximum animation scale factor. @@ -3134,6 +3134,41 @@ TEST_F(LegacySWPictureLayerImplTest, // we should not reset the scale factor. SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f); + + // Test that will-change:transform on an ancestor has the same + // effects. We happen to have the page scale layer as an ancestor, so + // just use that. + maximum_animation_scale = 2.f; + LayerImpl* active_page_scale_layer = + host_impl()->active_tree()->LayerById(active_layer()->id() - 1); + LayerImpl* pending_page_scale_layer = + host_impl()->pending_tree()->LayerById(pending_layer()->id() - 1); + DCHECK_EQ(GetTransformNode(active_page_scale_layer)->id, + GetTransformNode(active_layer())->parent_id); + DCHECK_EQ(GetTransformNode(pending_page_scale_layer)->id, + GetTransformNode(pending_layer())->parent_id); + SetWillChangeTransform(active_layer(), false); + SetWillChangeTransform(pending_layer(), false); + SetContentsScaleOnBothLayers(contents_scale * 2.f, device_scale, page_scale); + SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f); + SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale, + page_scale, maximum_animation_scale, + affected_by_invalid_scale); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f); + SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f); + SetWillChangeTransform(active_page_scale_layer, true); + SetWillChangeTransform(pending_page_scale_layer, true); + // re-set the false so node_or_ancestors_will_change_transform is recomputed + SetWillChangeTransform(active_layer(), false); + SetWillChangeTransform(pending_layer(), false); + SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale, + page_scale, maximum_animation_scale, + affected_by_invalid_scale); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f); + SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); + EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f); } TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimationAspectRatio) { @@ -3193,8 +3228,8 @@ TEST_F(LegacySWPictureLayerImplTest, // The clamping logic still works with will-change:transform. // Raster source size change forces adjustment of raster scale. - GetTransformNode(active_layer())->will_change_transform = true; - GetTransformNode(pending_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); + SetWillChangeTransform(pending_layer(), true); layer_bounds = gfx::Size(200, 200); Region invalidation; // UpdateRasterSource() requires that the pending tree doesn't have tiles. @@ -3674,8 +3709,8 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) { // If we change the layer contents scale after setting will change // will, then it will be updated if it's below the minimum scale (page scale * // device scale). - GetTransformNode(active_layer())->will_change_transform = true; - GetTransformNode(pending_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); + SetWillChangeTransform(pending_layer(), true); contents_scale = 0.75f; @@ -3698,8 +3733,8 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) { // Disabling the will-change hint will once again make the raster scale update // with the ideal scale. - GetTransformNode(active_layer())->will_change_transform = false; - GetTransformNode(pending_layer())->will_change_transform = false; + SetWillChangeTransform(active_layer(), false); + SetWillChangeTransform(pending_layer(), false); contents_scale = 3.f; @@ -3723,8 +3758,8 @@ TEST_F(LegacySWPictureLayerImplTest, TinyRasterScale) { // If we change the layer contents scale after setting will change // will, then it will be updated if it's below the minimum scale (page scale * // device scale). - GetTransformNode(active_layer())->will_change_transform = true; - GetTransformNode(pending_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); + SetWillChangeTransform(pending_layer(), true); SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); // The scale is clamped to the native scale. @@ -3760,8 +3795,8 @@ TEST_F(LegacySWPictureLayerImplTest, float contents_scale = 1.f; float device_scale = 1.f; float page_scale = 1.f; - GetTransformNode(active_layer())->will_change_transform = true; - GetTransformNode(pending_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); + SetWillChangeTransform(pending_layer(), true); SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale); EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f); @@ -4011,7 +4046,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) { float page_scale = 1.f; float scale = 1.f; - GetTransformNode(active_layer())->will_change_transform = true; + SetWillChangeTransform(active_layer(), true); ResetTilingsAndRasterScales(); SetContentsScaleOnBothLayers(scale, device_scale, page_scale); @@ -5682,21 +5717,27 @@ TEST_F(LegacySWPictureLayerImplTest, HighResWasLowResCollision) { TEST_F(LegacySWPictureLayerImplTest, CompositedImageCalculateContentsScale) { gfx::Size layer_bounds(400, 400); + gfx::Rect layer_rect(layer_bounds); + + host_impl()->active_tree()->SetDeviceViewportRect(layer_rect); + scoped_refptr<FakeRasterSource> pending_raster_source = FakeRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); - host_impl()->CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl()->pending_tree(); + const int kLayerId = 100; std::unique_ptr<FakePictureLayerImpl> pending_layer = - FakePictureLayerImpl::Create(pending_tree, root_id(), + FakePictureLayerImpl::Create(pending_tree, kLayerId, pending_raster_source); pending_layer->SetDirectlyCompositedImageDefaultRasterScale( gfx::Vector2dF(1, 1)); pending_layer->SetDrawsContent(true); FakePictureLayerImpl* pending_layer_ptr = pending_layer.get(); - pending_tree->SetRootLayerForTesting(std::move(pending_layer)); - SetupRootProperties(pending_layer_ptr); + pending_tree->AddLayer(std::move(pending_layer)); + CopyProperties(pending_tree->root_layer(), pending_layer_ptr); + UpdateDrawProperties(pending_tree); SetupDrawPropertiesAndUpdateTiles(pending_layer_ptr, 2.f, 3.f, 4.f); @@ -5706,23 +5747,26 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageCalculateContentsScale) { TEST_F(LegacySWPictureLayerImplTest, CompositedImageIgnoreIdealContentsScale) { gfx::Size layer_bounds(400, 400); gfx::Rect layer_rect(layer_bounds); + + host_impl()->active_tree()->SetDeviceViewportRect(layer_rect); + scoped_refptr<FakeRasterSource> pending_raster_source = FakeRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); - host_impl()->active_tree()->SetDeviceViewportRect(layer_rect); - host_impl()->CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl()->pending_tree(); + const int kLayerId = 100; std::unique_ptr<FakePictureLayerImpl> pending_layer = - FakePictureLayerImpl::Create(pending_tree, root_id(), + FakePictureLayerImpl::Create(pending_tree, kLayerId, pending_raster_source); pending_layer->SetDirectlyCompositedImageDefaultRasterScale( gfx::Vector2dF(1, 1)); pending_layer->SetDrawsContent(true); FakePictureLayerImpl* pending_layer_ptr = pending_layer.get(); - pending_tree->SetRootLayerForTesting(std::move(pending_layer)); - pending_tree->SetDeviceViewportRect(layer_rect); - SetupRootProperties(pending_layer_ptr); + pending_tree->AddLayer(std::move(pending_layer)); + CopyProperties(pending_tree->root_layer(), pending_layer_ptr); + UpdateDrawProperties(pending_tree); // Set PictureLayerImpl::ideal_contents_scale_ to 2.f. @@ -5739,7 +5783,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageIgnoreIdealContentsScale) { host_impl()->ActivateSyncTree(); FakePictureLayerImpl* active_layer = static_cast<FakePictureLayerImpl*>( - host_impl()->active_tree()->root_layer()); + host_impl()->active_tree()->LayerById(kLayerId)); SetupDrawPropertiesAndUpdateTiles(active_layer, suggested_ideal_contents_scale, device_scale_factor, page_scale_factor); @@ -6236,7 +6280,7 @@ TEST_F(LegacySWPictureLayerImplTest, FakeRasterSource::CreateFilledWithText(gfx::Size(200, 200)); SetupTreesWithInvalidation(raster_source, raster_source, Region()); - pending_layer()->SetBackgroundColor(SK_ColorWHITE); + pending_layer()->SetBackgroundColor(SkColors::kWhite); pending_layer()->SetContentsOpaque(true); pending_layer()->SetOffsetToTransformParent(gfx::Vector2dF(0.2, 0.3)); host_impl()->pending_tree()->set_needs_update_draw_properties(); @@ -6292,7 +6336,7 @@ TEST_F(LegacySWPictureLayerImplTest, auto raster_source = FakeRasterSource::CreateFilled(gfx::Size(200, 200)); SetupTreesWithInvalidation(raster_source, raster_source, Region()); - pending_layer()->SetBackgroundColor(SK_ColorWHITE); + pending_layer()->SetBackgroundColor(SkColors::kWhite); pending_layer()->SetContentsOpaque(true); pending_layer()->SetOffsetToTransformParent(gfx::Vector2dF(0.2, 0.3)); host_impl()->pending_tree()->set_needs_update_draw_properties(); @@ -6496,14 +6540,14 @@ TEST_P(LCDTextTest, Opacity) { TEST_P(LCDTextTest, ContentsNotOpaque) { // Non-opaque content and opaque background. layer_->SetContentsOpaque(false); - layer_->SetBackgroundColor(SK_ColorGREEN); + layer_->SetBackgroundColor(SkColors::kGreen); CheckCanUseLCDText(LCDTextDisallowedReason::kContentsNotOpaque, "contents not opaque", layer_); CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "descedant of contents not opaque", descendant_); // Non-opaque content and non-opaque background. - layer_->SetBackgroundColor(SkColorSetARGB(128, 255, 255, 255)); + layer_->SetBackgroundColor({1.0f, 1.0f, 1.0f, 0.5f}); CheckCanUseLCDText(LCDTextDisallowedReason::kBackgroundColorNotOpaque, "background not opaque", layer_); CheckCanUseLCDText(LCDTextDisallowedReason::kNone, @@ -6591,7 +6635,7 @@ TEST_P(LCDTextTest, BackdropFilterAnimation) { TEST_P(LCDTextTest, ContentsOpaqueForText) { layer_->SetContentsOpaque(false); - layer_->SetBackgroundColor(SK_ColorGREEN); + layer_->SetBackgroundColor(SkColors::kGreen); layer_->SetContentsOpaqueForText(true); CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "contents opaque for text", layer_); diff --git a/chromium/cc/layers/recording_source.cc b/chromium/cc/layers/recording_source.cc index 7e5de75f1f9..3d618c14319 100644 --- a/chromium/cc/layers/recording_source.cc +++ b/chromium/cc/layers/recording_source.cc @@ -115,7 +115,7 @@ void RecordingSource::SetSlowdownRasterScaleFactor(int factor) { slow_down_raster_scale_factor_for_debug_ = factor; } -void RecordingSource::SetBackgroundColor(SkColor background_color) { +void RecordingSource::SetBackgroundColor(SkColor4f background_color) { background_color_ = background_color; } @@ -130,7 +130,7 @@ scoped_refptr<RasterSource> RecordingSource::CreateRasterSource() const { void RecordingSource::DetermineIfSolidColor() { DCHECK(display_list_); is_solid_color_ = false; - solid_color_ = SK_ColorTRANSPARENT; + solid_color_ = SkColors::kTransparent; if (display_list_->TotalOpCount() > kMaxOpsToAnalyzeForLayer) return; diff --git a/chromium/cc/layers/recording_source.h b/chromium/cc/layers/recording_source.h index 0f9c6eff422..d0df0ac1429 100644 --- a/chromium/cc/layers/recording_source.h +++ b/chromium/cc/layers/recording_source.h @@ -36,7 +36,7 @@ class CC_EXPORT RecordingSource { gfx::Size GetSize() const; void SetEmptyBounds(); void SetSlowdownRasterScaleFactor(int factor); - void SetBackgroundColor(SkColor background_color); + void SetBackgroundColor(SkColor4f background_color); void SetRequiresClear(bool requires_clear); void SetNeedsDisplayRect(const gfx::Rect& layer_rect); @@ -52,8 +52,8 @@ class CC_EXPORT RecordingSource { int slow_down_raster_scale_factor_for_debug_ = 0; bool requires_clear_ = false; bool is_solid_color_ = false; - SkColor solid_color_ = SK_ColorTRANSPARENT; - SkColor background_color_ = SK_ColorTRANSPARENT; + SkColor4f solid_color_ = SkColors::kTransparent; + SkColor4f background_color_ = SkColors::kTransparent; scoped_refptr<DisplayItemList> display_list_; float recording_scale_factor_ = 1.0f; diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc index 6636586c4ff..d274baf743c 100644 --- a/chromium/cc/layers/render_surface_impl.cc +++ b/chromium/cc/layers/render_surface_impl.cc @@ -111,7 +111,8 @@ SkBlendMode RenderSurfaceImpl::BlendMode() const { } SkColor RenderSurfaceImpl::GetDebugBorderColor() const { - return DebugColors::SurfaceBorderColor(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + return DebugColors::SurfaceBorderColor().toSkColor(); } float RenderSurfaceImpl::GetDebugBorderWidth() const { diff --git a/chromium/cc/layers/solid_color_layer.cc b/chromium/cc/layers/solid_color_layer.cc index adf0319e52e..8cc831ed7fe 100644 --- a/chromium/cc/layers/solid_color_layer.cc +++ b/chromium/cc/layers/solid_color_layer.cc @@ -23,8 +23,8 @@ SolidColorLayer::SolidColorLayer() = default; SolidColorLayer::~SolidColorLayer() = default; -void SolidColorLayer::SetBackgroundColor(SkColor color) { - SetContentsOpaque(SkColorGetA(color) == 255); +void SolidColorLayer::SetBackgroundColor(SkColor4f color) { + SetContentsOpaque(color.isOpaque()); Layer::SetBackgroundColor(color); } diff --git a/chromium/cc/layers/solid_color_layer.h b/chromium/cc/layers/solid_color_layer.h index 77dabef7980..ea24db75029 100644 --- a/chromium/cc/layers/solid_color_layer.h +++ b/chromium/cc/layers/solid_color_layer.h @@ -25,7 +25,7 @@ class CC_EXPORT SolidColorLayer : public Layer { std::unique_ptr<LayerImpl> CreateLayerImpl( LayerTreeImpl* tree_impl) const override; - void SetBackgroundColor(SkColor color) override; + void SetBackgroundColor(SkColor4f color) override; protected: SolidColorLayer(); diff --git a/chromium/cc/layers/solid_color_layer_impl.cc b/chromium/cc/layers/solid_color_layer_impl.cc index 9baa31ce948..7e6332cf236 100644 --- a/chromium/cc/layers/solid_color_layer_impl.cc +++ b/chromium/cc/layers/solid_color_layer_impl.cc @@ -31,7 +31,7 @@ void SolidColorLayerImpl::AppendSolidQuads( const Occlusion& occlusion_in_layer_space, viz::SharedQuadState* shared_quad_state, const gfx::Rect& visible_layer_rect, - SkColor color, + SkColor4f color, bool force_anti_aliasing_off, SkBlendMode effect_blend_mode, AppendQuadsData* append_quads_data) { @@ -45,8 +45,7 @@ void SolidColorLayerImpl::AppendSolidQuads( // mask, but will not work in complex blend mode situations. This bug is // tracked in crbug.com/939168. if (effect_blend_mode == SkBlendMode::kSrcOver) { - float alpha = - (SkColorGetA(color) * (1.0f / 255.0f)) * shared_quad_state->opacity; + float alpha = color.fA * shared_quad_state->opacity; if (alpha < std::numeric_limits<float>::epsilon()) return; @@ -58,8 +57,9 @@ void SolidColorLayerImpl::AppendSolidQuads( return; auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - quad->SetNew(shared_quad_state, visible_layer_rect, visible_quad_rect, color, - force_anti_aliasing_off); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + quad->SetNew(shared_quad_state, visible_layer_rect, visible_quad_rect, + color.toSkColor(), force_anti_aliasing_off); } void SolidColorLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, diff --git a/chromium/cc/layers/solid_color_layer_impl.h b/chromium/cc/layers/solid_color_layer_impl.h index 2090424d5d2..321e6b2c3f7 100644 --- a/chromium/cc/layers/solid_color_layer_impl.h +++ b/chromium/cc/layers/solid_color_layer_impl.h @@ -27,7 +27,7 @@ class CC_EXPORT SolidColorLayerImpl : public LayerImpl { const Occlusion& occlusion_in_layer_space, viz::SharedQuadState* shared_quad_state, const gfx::Rect& visible_layer_rect, - SkColor color, + SkColor4f color, bool force_anti_aliasing_off, SkBlendMode effect_blend_mode, AppendQuadsData* append_quads_data); diff --git a/chromium/cc/layers/solid_color_layer_impl_unittest.cc b/chromium/cc/layers/solid_color_layer_impl_unittest.cc index c921c646df7..4b45a147510 100644 --- a/chromium/cc/layers/solid_color_layer_impl_unittest.cc +++ b/chromium/cc/layers/solid_color_layer_impl_unittest.cc @@ -33,7 +33,7 @@ TEST_F(SolidColorLayerImplTest, VerifyTilingCompleteAndNoOverlap) { auto* layer = AddLayer<SolidColorLayerImpl>(); layer->SetBounds(layer_size); layer->SetDrawsContent(true); - layer->SetBackgroundColor(SK_ColorRED); + layer->SetBackgroundColor(SkColors::kRed); CopyProperties(root_layer(), layer); CreateEffectNode(layer).render_surface_reason = RenderSurfaceReason::kTest; UpdateActiveTreeDrawProperties(); @@ -44,7 +44,10 @@ TEST_F(SolidColorLayerImplTest, VerifyTilingCompleteAndNoOverlap) { } TEST_F(SolidColorLayerImplTest, VerifyCorrectBackgroundColorInQuad) { - SkColor test_color = 0xFFA55AFF; + // TODO(crbug.com/1308932): Somewhere along the path this gets cast to an int + // so the test fails if the values are not x/255. This should not be the case + // when the SkColor4f project is completed. + SkColor4f test_color{165.0f / 255.0f, 90.0f / 255.0f, 1.0f, 1.0f}; auto render_pass = viz::CompositorRenderPass::Create(); gfx::Size layer_size = gfx::Size(100, 100); gfx::Rect visible_layer_rect = gfx::Rect(layer_size); @@ -78,7 +81,7 @@ TEST_F(SolidColorLayerImplTest, VerifyCorrectOpacityInQuad) { auto* layer = AddLayer<SolidColorLayerImpl>(); layer->SetDrawsContent(true); layer->SetBounds(layer_size); - layer->SetBackgroundColor(SK_ColorRED); + layer->SetBackgroundColor(SkColors::kRed); CopyProperties(root_layer(), layer); auto& effect_node = CreateEffectNode(layer); effect_node.opacity = opacity; @@ -104,7 +107,7 @@ TEST_F(SolidColorLayerImplTest, VerifyCorrectRenderSurfaceOpacityInQuad) { auto* layer = AddLayer<SolidColorLayerImpl>(); layer->SetDrawsContent(true); layer->SetBounds(layer_size); - layer->SetBackgroundColor(SK_ColorRED); + layer->SetBackgroundColor(SkColors::kRed); CopyProperties(root_layer(), layer); auto& effect_node = CreateEffectNode(layer); effect_node.render_surface_reason = RenderSurfaceReason::kTest; @@ -126,7 +129,7 @@ TEST_F(SolidColorLayerImplTest, VerifyCorrectRenderSurfaceOpacityInQuad) { } TEST_F(SolidColorLayerImplTest, VerifyEliminateTransparentAlpha) { - SkColor test_color = 0; + SkColor4f test_color = SkColors::kTransparent; auto render_pass = viz::CompositorRenderPass::Create(); gfx::Size layer_size = gfx::Size(100, 100); @@ -144,7 +147,7 @@ TEST_F(SolidColorLayerImplTest, VerifyEliminateTransparentAlpha) { } TEST_F(SolidColorLayerImplTest, VerifyEliminateTransparentOpacity) { - SkColor test_color = 0xFFA55AFF; + SkColor4f test_color{0.5f, 0.8f, 1.0f, 1.0f}; auto render_pass = viz::CompositorRenderPass::Create(); gfx::Size layer_size = gfx::Size(100, 100); @@ -184,7 +187,7 @@ TEST_F(SolidColorLayerImplTest, VerifyNeedsBlending) { UpdateDrawProperties(host.get()); EXPECT_FALSE(layer->contents_opaque()); - layer->SetBackgroundColor(SkColorSetARGB(255, 10, 20, 30)); + layer->SetBackgroundColor({0.2f, 0.3f, 0.4f, 1.0f}); EXPECT_TRUE(layer->contents_opaque()); auto& unsafe_state = host->GetUnsafeStateForCommit(); @@ -220,7 +223,7 @@ TEST_F(SolidColorLayerImplTest, VerifyNeedsBlending) { host->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()}); EXPECT_TRUE(layer->contents_opaque()); - layer->SetBackgroundColor(SkColorSetARGB(254, 10, 20, 30)); + layer->SetBackgroundColor({0.2f, 0.3f, 0.4f, 0.9f}); EXPECT_FALSE(layer->contents_opaque()); completion_event_ptr = std::make_unique<CompletionEvent>( @@ -260,7 +263,7 @@ TEST_F(SolidColorLayerImplTest, Occlusion) { gfx::Size viewport_size(1000, 1000); auto* solid_color_layer_impl = AddLayer<SolidColorLayerImpl>(); - solid_color_layer_impl->SetBackgroundColor(SkColorSetARGB(255, 10, 20, 30)); + solid_color_layer_impl->SetBackgroundColor({0.1f, 0.2f, 0.3f, 1.0f}); solid_color_layer_impl->SetBounds(layer_size); solid_color_layer_impl->SetDrawsContent(true); CopyProperties(root_layer(), solid_color_layer_impl); diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc index 8a3f3a2f460..f1b8b88edf3 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc @@ -50,7 +50,9 @@ SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl( /*is_overlay*/ true), thumb_thickness_(thumb_thickness), track_start_(track_start), - color_(tree_impl->settings().solid_color_scrollbar_color) {} + // TODO(crbug/1308932): Remove FromColor and make all SkColor4f. + color_(SkColor4f::FromColor( + tree_impl->settings().solid_color_scrollbar_color)) {} void SolidColorScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) { ScrollbarLayerImplBase::PushPropertiesTo(layer); @@ -106,8 +108,9 @@ void SolidColorScrollbarLayerImpl::AppendQuads( return; auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - quad->SetNew( - shared_quad_state, thumb_quad_rect, visible_quad_rect, color_, false); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + quad->SetNew(shared_quad_state, thumb_quad_rect, visible_quad_rect, + color_.toSkColor(), false); } const char* SolidColorScrollbarLayerImpl::LayerTypeAsString() const { diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h index 6aff854d3f5..2c688ed4c4d 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h +++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h @@ -52,7 +52,7 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase { int thumb_thickness_; int track_start_; - SkColor color_; + SkColor4f color_; }; } // namespace cc diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc index b58be0601fa..c3050488efb 100644 --- a/chromium/cc/layers/surface_layer_impl.cc +++ b/chromium/cc/layers/surface_layer_impl.cc @@ -182,8 +182,9 @@ void SurfaceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, if (surface_range_.IsValid()) { auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, - surface_range_, background_color(), + surface_range_, background_color().toSkColor(), stretch_content_to_fill_bounds_); quad->is_reflection = is_reflection_; // Add the primary surface ID as a dependency. @@ -199,8 +200,10 @@ void SurfaceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, } else { auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, - background_color(), false /* force_anti_aliasing_off */); + background_color().toSkColor(), + false /* force_anti_aliasing_off */); } // Unless the client explicitly specifies otherwise, don't block on @@ -217,7 +220,7 @@ gfx::Rect SurfaceLayerImpl::GetEnclosingVisibleRectInTargetSpace() const { layer_tree_impl()->device_scale_factor()); } -void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color, +void SurfaceLayerImpl::GetDebugBorderProperties(SkColor4f* color, float* width) const { *color = DebugColors::SurfaceLayerBorderColor(); *width = DebugColors::SurfaceLayerBorderWidth( @@ -233,7 +236,7 @@ void SurfaceLayerImpl::AppendRainbowDebugBorder( render_pass->CreateAndAppendSharedQuadState(); PopulateSharedQuadState(shared_quad_state, contents_opaque()); - SkColor color; + SkColor4f color; float border_width; GetDebugBorderProperties(&color, &border_width); diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h index 12174b65cbb..936028b65d9 100644 --- a/chromium/cc/layers/surface_layer_impl.h +++ b/chromium/cc/layers/surface_layer_impl.h @@ -75,7 +75,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl { SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id, UpdateSubmissionStateCB); private: - void GetDebugBorderProperties(SkColor* color, float* width) const override; + void GetDebugBorderProperties(SkColor4f* color, float* width) const override; void AppendRainbowDebugBorder(viz::CompositorRenderPass* render_pass); void AsValueInto(base::trace_event::TracedValue* dict) const override; const char* LayerTypeAsString() const override; diff --git a/chromium/cc/layers/surface_layer_impl_unittest.cc b/chromium/cc/layers/surface_layer_impl_unittest.cc index dae84867f66..808aeea3fc9 100644 --- a/chromium/cc/layers/surface_layer_impl_unittest.cc +++ b/chromium/cc/layers/surface_layer_impl_unittest.cc @@ -97,7 +97,7 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplWithTwoDifferentSurfaces) { surface_layer_impl->SetBounds(layer_size); surface_layer_impl->SetDrawsContent(true); surface_layer_impl->SetRange(viz::SurfaceRange(surface_id2, surface_id1), 2u); - surface_layer_impl->SetBackgroundColor(SK_ColorBLUE); + surface_layer_impl->SetBackgroundColor(SkColors::kBlue); CopyProperties(impl.root_layer(), surface_layer_impl); gfx::Size viewport_size(1000, 1000); @@ -159,15 +159,15 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplWithTwoDifferentSurfaces) { ASSERT_TRUE(surface_draw_quad3); EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.end()); - EXPECT_EQ(SK_ColorBLUE, surface_draw_quad1->default_background_color); + EXPECT_EQ(SkColors::kBlue, surface_draw_quad1->default_background_color); EXPECT_EQ(surface_id2, surface_draw_quad1->surface_range.start()); EXPECT_EQ(surface_id1, surface_draw_quad2->surface_range.end()); - EXPECT_EQ(SK_ColorBLUE, surface_draw_quad2->default_background_color); + EXPECT_EQ(SkColors::kBlue, surface_draw_quad2->default_background_color); EXPECT_EQ(absl::nullopt, surface_draw_quad2->surface_range.start()); EXPECT_EQ(surface_id1, surface_draw_quad3->surface_range.end()); - EXPECT_EQ(SK_ColorBLUE, surface_draw_quad3->default_background_color); + EXPECT_EQ(SkColors::kBlue, surface_draw_quad3->default_background_color); EXPECT_EQ(surface_id2, surface_draw_quad3->surface_range.start()); } @@ -235,7 +235,7 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplWithMatchingPrimaryAndFallback) { surface_layer_impl->SetDrawsContent(true); surface_layer_impl->SetRange(viz::SurfaceRange(surface_id1), 1u); surface_layer_impl->SetRange(viz::SurfaceRange(surface_id1), 2u); - surface_layer_impl->SetBackgroundColor(SK_ColorBLUE); + surface_layer_impl->SetBackgroundColor(SkColors::kBlue); CopyProperties(impl.root_layer(), surface_layer_impl); gfx::Size viewport_size(1000, 1000); @@ -254,7 +254,7 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplWithMatchingPrimaryAndFallback) { EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.end()); EXPECT_EQ(surface_id1, surface_draw_quad1->surface_range.start()); - EXPECT_EQ(SK_ColorBLUE, surface_draw_quad1->default_background_color); + EXPECT_EQ(SkColors::kBlue, surface_draw_quad1->default_background_color); } TEST(SurfaceLayerImplTest, GetEnclosingRectInTargetSpace) { diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc index 2ba3751761c..f70a27470e8 100644 --- a/chromium/cc/layers/surface_layer_unittest.cc +++ b/chromium/cc/layers/surface_layer_unittest.cc @@ -138,7 +138,7 @@ TEST_F(SurfaceLayerTest, PushProperties) { layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(2u)); layer->SetSurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); layer->SetOldestAcceptableFallback(primary_id); - layer->SetBackgroundColor(SK_ColorBLUE); + layer->SetBackgroundColor(SkColors::kBlue); layer->SetStretchContentToFillBounds(true); EXPECT_TRUE( @@ -166,7 +166,7 @@ TEST_F(SurfaceLayerTest, PushProperties) { // Verify that the primary and fallback SurfaceIds are pushed through. EXPECT_EQ(primary_id, layer_impl->range().end()); EXPECT_EQ(primary_id, layer_impl->range().start()); - EXPECT_EQ(SK_ColorBLUE, layer_impl->background_color()); + EXPECT_EQ(SkColors::kBlue, layer_impl->background_color()); EXPECT_TRUE(layer_impl->stretch_content_to_fill_bounds()); EXPECT_EQ(2u, layer_impl->deadline_in_frames()); @@ -175,7 +175,7 @@ TEST_F(SurfaceLayerTest, PushProperties) { viz::LocalSurfaceId(2, base::UnguessableToken::Create())); layer->SetOldestAcceptableFallback(fallback_id); layer->SetSurfaceId(fallback_id, DeadlinePolicy::UseExistingDeadline()); - layer->SetBackgroundColor(SK_ColorGREEN); + layer->SetBackgroundColor(SkColors::kGreen); layer->SetStretchContentToFillBounds(false); // Verify that fallback surface id is not recorded on the layer tree host as @@ -193,7 +193,7 @@ TEST_F(SurfaceLayerTest, PushProperties) { // fallback viz::SurfaceId is pushed through. EXPECT_EQ(fallback_id, layer_impl->range().end()); EXPECT_EQ(fallback_id, layer_impl->range().start()); - EXPECT_EQ(SK_ColorGREEN, layer_impl->background_color()); + EXPECT_EQ(SkColors::kGreen, layer_impl->background_color()); // The deadline resets back to 0 (no deadline) after the first commit. EXPECT_EQ(0u, layer_impl->deadline_in_frames()); EXPECT_FALSE(layer_impl->stretch_content_to_fill_bounds()); diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc index 8b9bf91efff..a41414dbaf3 100644 --- a/chromium/cc/layers/texture_layer_impl.cc +++ b/chromium/cc/layers/texture_layer_impl.cc @@ -122,15 +122,14 @@ void TextureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, std::make_move_iterator(to_register_bitmaps_.end())); to_register_bitmaps_.clear(); - SkColor bg_color = - blend_background_color_ ? background_color() : SK_ColorTRANSPARENT; + SkColor4f bg_color = + blend_background_color_ ? background_color() : SkColors::kTransparent; if (force_texture_to_opaque_) { - bg_color = SK_ColorBLACK; + bg_color = SkColors::kBlack; } - bool are_contents_opaque = - contents_opaque() || (SkColorGetA(bg_color) == 0xFF); + bool are_contents_opaque = contents_opaque() || bg_color.isOpaque(); viz::SharedQuadState* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); @@ -148,11 +147,12 @@ void TextureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass, return; float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>(); quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, needs_blending, resource_id_, premultiplied_alpha_, uv_top_left_, - uv_bottom_right_, bg_color, vertex_opacity, flipped_, - nearest_neighbor_, /*secure_output_only=*/false, + uv_bottom_right_, bg_color.toSkColor(), vertex_opacity, flipped_, + nearest_neighbor_, /*secure_output=*/false, gfx::ProtectedVideoType::kClear); quad->set_resource_size_in_pixels(transferable_resource_.size); ValidateQuadResources(quad); @@ -165,7 +165,7 @@ SimpleEnclosedRegion TextureLayerImpl::VisibleOpaqueRegion() const { if (force_texture_to_opaque_) return SimpleEnclosedRegion(visible_layer_rect()); - if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF)) + if (blend_background_color_ && background_color().isOpaque()) return SimpleEnclosedRegion(visible_layer_rect()); return SimpleEnclosedRegion(); diff --git a/chromium/cc/layers/texture_layer_impl_unittest.cc b/chromium/cc/layers/texture_layer_impl_unittest.cc index 5ba92ea9c09..dc36daac534 100644 --- a/chromium/cc/layers/texture_layer_impl_unittest.cc +++ b/chromium/cc/layers/texture_layer_impl_unittest.cc @@ -36,15 +36,15 @@ TEST(TextureLayerImplTest, VisibleOpaqueRegion) { // Verify initial conditions. EXPECT_FALSE(layer->contents_opaque()); - EXPECT_EQ(0u, layer->background_color()); + EXPECT_EQ(SkColors::kTransparent, layer->background_color()); EXPECT_EQ(Region().ToString(), layer->VisibleOpaqueRegion().ToString()); // Opaque background. - layer->SetBackgroundColor(SK_ColorWHITE); + layer->SetBackgroundColor(SkColors::kWhite); EXPECT_EQ(layer_region.ToString(), layer->VisibleOpaqueRegion().ToString()); // Transparent background. - layer->SetBackgroundColor(SkColorSetARGB(100, 255, 255, 255)); + layer->SetBackgroundColor({1.0f, 1.0f, 1.0f, 0.5f}); EXPECT_EQ(Region().ToString(), layer->VisibleOpaqueRegion().ToString()); } diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc index 945dec20616..3a8feebbfbf 100644 --- a/chromium/cc/layers/texture_layer_unittest.cc +++ b/chromium/cc/layers/texture_layer_unittest.cc @@ -1031,7 +1031,7 @@ class TextureLayerChangeInvisibleMailboxTest solid_layer_ = SolidColorLayer::Create(); solid_layer_->SetBounds(gfx::Size(10, 10)); solid_layer_->SetIsDrawable(true); - solid_layer_->SetBackgroundColor(SK_ColorWHITE); + solid_layer_->SetBackgroundColor(SkColors::kWhite); root->AddChild(solid_layer_); parent_layer_ = Layer::Create(); @@ -1067,7 +1067,7 @@ class TextureLayerChangeInvisibleMailboxTest resource_changed_ = true; texture_layer_->SetNeedsDisplay(); // Force a change to make sure we draw a frame. - solid_layer_->SetBackgroundColor(SK_ColorGRAY); + solid_layer_->SetBackgroundColor(SkColors::kGray); break; case 3: // Layer shouldn't have been updated. @@ -1383,7 +1383,7 @@ class SoftwareTextureLayerTest : public LayerTreeTest { // A drawable layer so that frames always get drawn. solid_color_layer_ = SolidColorLayer::Create(); solid_color_layer_->SetIsDrawable(true); - solid_color_layer_->SetBackgroundColor(SK_ColorRED); + solid_color_layer_->SetBackgroundColor(SkColors::kRed); solid_color_layer_->SetBounds(gfx::Size(10, 10)); root_->AddChild(solid_color_layer_); diff --git a/chromium/cc/layers/tile_size_calculator.cc b/chromium/cc/layers/tile_size_calculator.cc index ac95636f516..305ff973a97 100644 --- a/chromium/cc/layers/tile_size_calculator.cc +++ b/chromium/cc/layers/tile_size_calculator.cc @@ -121,7 +121,7 @@ gfx::Size CalculateGpuRawDrawTileSize(const gfx::Size& base_tile_size, // AffectingParams. bool TileSizeCalculator::AffectingParams::operator==( - const AffectingParams& other) { + const AffectingParams& other) const { return max_texture_size == other.max_texture_size && use_gpu_rasterization == other.use_gpu_rasterization && device_scale_factor == other.device_scale_factor && diff --git a/chromium/cc/layers/tile_size_calculator.h b/chromium/cc/layers/tile_size_calculator.h index e4616b8c67d..c79bc2ba5f7 100644 --- a/chromium/cc/layers/tile_size_calculator.h +++ b/chromium/cc/layers/tile_size_calculator.h @@ -33,7 +33,7 @@ class CC_EXPORT TileSizeCalculator { gfx::Size default_tile_size; gfx::Size layer_content_bounds; - bool operator==(const AffectingParams& other); + bool operator==(const AffectingParams& other) const; }; PictureLayerImpl* layer_impl() const { return layer_impl_; } diff --git a/chromium/cc/layers/video_frame_provider.h b/chromium/cc/layers/video_frame_provider.h index 7ae08903b6b..7dff50c3ede 100644 --- a/chromium/cc/layers/video_frame_provider.h +++ b/chromium/cc/layers/video_frame_provider.h @@ -97,6 +97,10 @@ class CC_EXPORT VideoFrameProvider { // the client. virtual base::TimeDelta GetPreferredRenderInterval() = 0; + // Inform the provider that the context is lost. The provider need to reset + // the current frame if it's invald. + virtual void OnContextLost() = 0; + protected: virtual ~VideoFrameProvider() {} }; diff --git a/chromium/cc/metrics/begin_main_frame_metrics.h b/chromium/cc/metrics/begin_main_frame_metrics.h index e9e479c2d5d..d12efb8c8f4 100644 --- a/chromium/cc/metrics/begin_main_frame_metrics.h +++ b/chromium/cc/metrics/begin_main_frame_metrics.h @@ -20,6 +20,7 @@ struct CC_EXPORT BeginMainFrameMetrics { base::TimeDelta animate; base::TimeDelta style_update; base::TimeDelta layout_update; + base::TimeDelta accessibility; base::TimeDelta prepaint; base::TimeDelta compositing_inputs; base::TimeDelta paint; diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc index d3ecb6bb3d5..fb5bdb10ff0 100644 --- a/chromium/cc/metrics/compositor_frame_reporter.cc +++ b/chromium/cc/metrics/compositor_frame_reporter.cc @@ -21,6 +21,7 @@ #include "cc/base/rolling_time_delta_history.h" #include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_latency_tracing_recorder.h" +#include "cc/metrics/event_latency_tracker.h" #include "cc/metrics/frame_sequence_tracker.h" #include "cc/metrics/latency_ukm_reporter.h" #include "services/tracing/public/cpp/perfetto/macros.h" @@ -180,6 +181,8 @@ CompositorFrameReporter::ProcessedBlinkBreakdown::ProcessedBlinkBreakdown( blink_breakdown.style_update; list_[static_cast<int>(BlinkBreakdown::kLayoutUpdate)] = blink_breakdown.layout_update; + list_[static_cast<int>(BlinkBreakdown::kAccessibility)] = + blink_breakdown.accessibility; list_[static_cast<int>(BlinkBreakdown::kPrepaint)] = blink_breakdown.prepaint; list_[static_cast<int>(BlinkBreakdown::kCompositingInputs)] = blink_breakdown.compositing_inputs; @@ -320,18 +323,19 @@ CompositorFrameReporter::ProcessedVizBreakdown::CreateIterator( CompositorFrameReporter::CompositorFrameReporter( const ActiveTrackers& active_trackers, const viz::BeginFrameArgs& args, - bool should_report_metrics, + bool should_report_histograms, SmoothThread smooth_thread, FrameInfo::SmoothEffectDrivingThread scrolling_thread, int layer_tree_host_id, const GlobalMetricsTrackers& trackers) - : should_report_metrics_(should_report_metrics), + : should_report_histograms_(should_report_histograms), args_(args), active_trackers_(active_trackers), scrolling_thread_(scrolling_thread), smooth_thread_(smooth_thread), layer_tree_host_id_(layer_tree_host_id), global_trackers_(trackers) { + DCHECK(global_trackers_.dropped_frame_counter); global_trackers_.dropped_frame_counter->OnBeginFrame( args, IsScrollActive(active_trackers_)); DCHECK(IsScrollActive(active_trackers_) || @@ -343,6 +347,16 @@ CompositorFrameReporter::CompositorFrameReporter( DCHECK(smooth_thread_ == SmoothThread::kSmoothMain || smooth_thread_ == SmoothThread::kSmoothBoth); } + // If we have a SET version of the animation, then we should also have a + // non-SET version of the same animation. + DCHECK(!active_trackers_.test(static_cast<size_t>( + FrameSequenceTrackerType::kSETCompositorAnimation)) || + active_trackers_.test(static_cast<size_t>( + FrameSequenceTrackerType::kCompositorAnimation))); + DCHECK(!active_trackers_.test(static_cast<size_t>( + FrameSequenceTrackerType::kSETMainThreadAnimation)) || + active_trackers_.test(static_cast<size_t>( + FrameSequenceTrackerType::kMainThreadAnimation))); } // static @@ -374,6 +388,8 @@ const char* CompositorFrameReporter::GetStageName( return "SendBeginMainFrameToCommit.StyleUpdate"; case BlinkBreakdown::kLayoutUpdate: return "SendBeginMainFrameToCommit.LayoutUpdate"; + case BlinkBreakdown::kAccessibility: + return "SendBeginMainFrameToCommit.AccessibiltyUpdate"; case BlinkBreakdown::kPrepaint: return "SendBeginMainFrameToCommit.Prepaint"; case BlinkBreakdown::kCompositingInputs: @@ -483,7 +499,7 @@ CompositorFrameReporter::CopyReporterAtBeginImplStage() { return nullptr; } auto new_reporter = std::make_unique<CompositorFrameReporter>( - active_trackers_, args_, should_report_metrics_, smooth_thread_, + active_trackers_, args_, should_report_histograms_, smooth_thread_, scrolling_thread_, layer_tree_host_id_, global_trackers_); new_reporter->did_finish_impl_frame_ = did_finish_impl_frame_; new_reporter->impl_frame_finish_time_ = impl_frame_finish_time_; @@ -604,6 +620,21 @@ EventMetrics::List CompositorFrameReporter::TakeEventsMetrics() { return result; } +EventMetrics::List CompositorFrameReporter::TakeMainBlockedEventsMetrics() { + auto mid = std::partition(events_metrics_.begin(), events_metrics_.end(), + [](std::unique_ptr<EventMetrics>& metrics) { + DCHECK(metrics); + bool is_blocked_on_main = + metrics->requires_main_thread_update(); + // Invert so we can take from the end. + return !is_blocked_on_main; + }); + EventMetrics::List result(std::make_move_iterator(mid), + std::make_move_iterator(events_metrics_.end())); + events_metrics_.erase(mid, events_metrics_.end()); + return result; +} + void CompositorFrameReporter::TerminateReporter() { if (frame_termination_status_ == FrameTerminationStatus::kUnknown) TerminateFrame(FrameTerminationStatus::kUnknown, Now()); @@ -647,8 +678,10 @@ void CompositorFrameReporter::TerminateReporter() { if (TestReportType(FrameReportType::kNonDroppedFrame)) ReportEventLatencyTraceEvents(); - // Only report compositor latency histograms if the frame was produced. - if (should_report_metrics_ && report_types_.any()) { + // Only report compositor latency metrics if the frame was produced. + if (report_types_.any() && + (should_report_histograms_ || global_trackers_.latency_ukm_reporter || + global_trackers_.event_latency_tracker)) { DCHECK(stage_history_.size()); DCHECK_EQ(SumOfStageHistory(), stage_history_.back().end_time - stage_history_.front().start_time); @@ -656,25 +689,22 @@ void CompositorFrameReporter::TerminateReporter() { stage_history_.front().start_time, stage_history_.back().end_time); - ReportCompositorLatencyHistograms(); - // Only report event latency histograms if the frame was presented. + ReportCompositorLatencyMetrics(); + + // Only report event latency metrics if the frame was presented. if (TestReportType(FrameReportType::kNonDroppedFrame)) - ReportEventLatencyHistograms(); + ReportEventLatencyMetrics(); } - auto* dropped_frame_counter = global_trackers_.dropped_frame_counter; - if (dropped_frame_counter) { - if (TestReportType(FrameReportType::kDroppedFrame)) { - dropped_frame_counter->AddDroppedFrame(); - } else { - if (has_partial_update_) - dropped_frame_counter->AddPartialFrame(); - else - dropped_frame_counter->AddGoodFrame(); - } - - dropped_frame_counter->OnEndFrame(args_, frame_info); + if (TestReportType(FrameReportType::kDroppedFrame)) { + global_trackers_.dropped_frame_counter->AddDroppedFrame(); + } else { + if (has_partial_update_) + global_trackers_.dropped_frame_counter->AddPartialFrame(); + else + global_trackers_.dropped_frame_counter->AddGoodFrame(); } + global_trackers_.dropped_frame_counter->OnEndFrame(args_, frame_info); if (discarded_partial_update_dependents_count_ > 0) UMA_HISTOGRAM_CUSTOM_COUNTS( @@ -690,10 +720,20 @@ void CompositorFrameReporter::EndCurrentStage(base::TimeTicks end_time) { current_stage_.start_time = base::TimeTicks(); } -void CompositorFrameReporter::ReportCompositorLatencyHistograms() const { +void CompositorFrameReporter::ReportCompositorLatencyMetrics() const { static base::CpuReductionExperimentFilter filter; if (!filter.ShouldLogHistograms()) return; + + if (global_trackers_.latency_ukm_reporter) { + global_trackers_.latency_ukm_reporter->ReportCompositorLatencyUkm( + report_types_, stage_history_, active_trackers_, + *processed_blink_breakdown_, *processed_viz_breakdown_); + } + + if (!should_report_histograms_) + return; + for (const StageData& stage : stage_history_) { ReportStageHistogramWithBreakdown(stage); @@ -708,12 +748,6 @@ void CompositorFrameReporter::ReportCompositorLatencyHistograms() const { } } - if (global_trackers_.latency_ukm_reporter) { - global_trackers_.latency_ukm_reporter->ReportCompositorLatencyUkm( - report_types_, stage_history_, active_trackers_, - *processed_blink_breakdown_, *processed_viz_breakdown_); - } - for (size_t type = 0; type < report_types_.size(); ++type) { if (!report_types_.test(type)) continue; @@ -768,6 +802,14 @@ void CompositorFrameReporter::ReportCompositorLatencyHistograms() const { UMA_HISTOGRAM_ENUMERATION("CompositorLatency.Type.JSAnimation", report_type); break; + case FrameSequenceTrackerType::kSETCompositorAnimation: + UMA_HISTOGRAM_ENUMERATION( + "CompositorLatency.Type.SETCompositorAnimation", report_type); + break; + case FrameSequenceTrackerType::kSETMainThreadAnimation: + UMA_HISTOGRAM_ENUMERATION( + "CompositorLatency.Type.SETMainThreadAnimation", report_type); + break; case FrameSequenceTrackerType::kCustom: case FrameSequenceTrackerType::kMaxType: NOTREACHED(); @@ -884,62 +926,84 @@ void CompositorFrameReporter::ReportCompositorLatencyHistogram( } } -void CompositorFrameReporter::ReportEventLatencyHistograms() const { +void CompositorFrameReporter::ReportEventLatencyMetrics() const { const StageData& total_latency_stage = stage_history_.back(); DCHECK_EQ(StageType::kTotalLatency, total_latency_stage.stage_type); - const std::string total_latency_stage_name = - GetStageName(StageType::kTotalLatency); - const std::string total_latency_histogram_name = - "EventLatency." + total_latency_stage_name; + if (global_trackers_.latency_ukm_reporter) { + global_trackers_.latency_ukm_reporter->ReportEventLatencyUkm( + events_metrics_, stage_history_, *processed_blink_breakdown_, + *processed_viz_breakdown_); + } + + std::vector<EventLatencyTracker::LatencyData> latencies; for (const auto& event_metrics : events_metrics_) { DCHECK(event_metrics); - const std::string histogram_base_name = - GetEventLatencyHistogramBaseName(*event_metrics); - const int event_type_index = static_cast<int>(event_metrics->type()); auto* scroll_metrics = event_metrics->AsScroll(); auto* pinch_metrics = event_metrics->AsPinch(); - const int gesture_type_index = - scroll_metrics - ? static_cast<int>(scroll_metrics->scroll_type()) - : pinch_metrics ? static_cast<int>(pinch_metrics->pinch_type()) : 0; - const int event_histogram_index = - event_type_index * kEventLatencyGestureTypeCount + gesture_type_index; const base::TimeTicks generated_timestamp = event_metrics->GetDispatchStageTimestamp( EventMetrics::DispatchStage::kGenerated); - DCHECK_LT(generated_timestamp, total_latency_stage.end_time); - - // Report total latency up to presentation for the event. + // Generally, we expect that the event timestamp is strictly smaller than + // the end timestamp of the last stage (i.e. total latency is positive); + // however, at least in tests, it is possible that the timestamps are the + // same and total latency is zero. + DCHECK_LE(generated_timestamp, total_latency_stage.end_time); const base::TimeDelta total_latency = total_latency_stage.end_time - generated_timestamp; - const std::string event_total_latency_histogram_name = - base::StrCat({histogram_base_name, ".", total_latency_stage_name}); - // Note: There's a 1:1 mapping between `event_histogram_index` and - // `event_total_latency_histogram_name` which allows the use of - // `STATIC_HISTOGRAM_POINTER_GROUP()` to cache histogram objects. - STATIC_HISTOGRAM_POINTER_GROUP( - event_total_latency_histogram_name, event_histogram_index, - kMaxEventLatencyHistogramIndex, - AddTimeMicrosecondsGranularity(total_latency), - base::Histogram::FactoryMicrosecondsTimeGet( - event_total_latency_histogram_name, kEventLatencyHistogramMin, - kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount, - base::HistogramBase::kUmaTargetedHistogramFlag)); - // Also, report total latency up to presentation for all event types in an - // aggregate histogram. - UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( - total_latency_histogram_name, total_latency, kEventLatencyHistogramMin, - kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount); + if (should_report_histograms_) { + const std::string histogram_base_name = + GetEventLatencyHistogramBaseName(*event_metrics); + const int event_type_index = static_cast<int>(event_metrics->type()); + const int gesture_type_index = + scroll_metrics ? static_cast<int>(scroll_metrics->scroll_type()) + : pinch_metrics ? static_cast<int>(pinch_metrics->pinch_type()) + : 0; + const int event_histogram_index = + event_type_index * kEventLatencyGestureTypeCount + gesture_type_index; + + const std::string total_latency_stage_name = + GetStageName(StageType::kTotalLatency); + const std::string event_total_latency_histogram_name = + base::StrCat({histogram_base_name, ".", total_latency_stage_name}); + // Note: There's a 1:1 mapping between `event_histogram_index` and + // `event_total_latency_histogram_name` which allows the use of + // `STATIC_HISTOGRAM_POINTER_GROUP()` to cache histogram objects. + STATIC_HISTOGRAM_POINTER_GROUP( + event_total_latency_histogram_name, event_histogram_index, + kMaxEventLatencyHistogramIndex, + AddTimeMicrosecondsGranularity(total_latency), + base::Histogram::FactoryMicrosecondsTimeGet( + event_total_latency_histogram_name, kEventLatencyHistogramMin, + kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount, + base::HistogramBase::kUmaTargetedHistogramFlag)); + + // Also, report total latency up to presentation for all event types in an + // aggregate histogram. + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "EventLatency." + total_latency_stage_name, total_latency, + kEventLatencyHistogramMin, kEventLatencyHistogramMax, + kEventLatencyHistogramBucketCount); + } + + if (global_trackers_.event_latency_tracker) { + EventLatencyTracker::LatencyData& latency_data = + latencies.emplace_back(event_metrics->type(), total_latency); + + if (scroll_metrics) + latency_data.input_type = scroll_metrics->scroll_type(); + else if (pinch_metrics) + latency_data.input_type = pinch_metrics->pinch_type(); + } } - if (global_trackers_.latency_ukm_reporter) { - global_trackers_.latency_ukm_reporter->ReportEventLatencyUkm( - events_metrics_, stage_history_, *processed_blink_breakdown_, - *processed_viz_breakdown_); + if (!latencies.empty()) { + DCHECK(global_trackers_.event_latency_tracker); + global_trackers_.event_latency_tracker->ReportEventLatency( + std::move(latencies)); } } @@ -1049,6 +1113,9 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents( case static_cast<int>(BlinkBreakdown::kLayoutUpdate): reporter->set_layout_update_us(latency); break; + case static_cast<int>(BlinkBreakdown::kAccessibility): + reporter->set_accessibility_update_us(latency); + break; case static_cast<int>(BlinkBreakdown::kPrepaint): reporter->set_prepaint_us(latency); break; @@ -1129,6 +1196,11 @@ void CompositorFrameReporter::AdoptReporter( // update, then |this| should not have any such dependents. DCHECK(!partial_update_decider_); DCHECK(!partial_update_dependents_.empty()); + + // The adoptee tracks a partial update. If it has metrics that depend on the + // main thread update, move them into |this| reporter. + AddEventsMetrics(reporter->TakeMainBlockedEventsMetrics()); + owned_partial_update_dependents_.push(std::move(reporter)); DiscardOldPartialUpdateReporters(); } diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h index f903e3d2155..ad0b1084a34 100644 --- a/chromium/cc/metrics/compositor_frame_reporter.h +++ b/chromium/cc/metrics/compositor_frame_reporter.h @@ -31,14 +31,16 @@ struct FrameTimingDetails; } namespace cc { -class FrameSequenceTrackerCollection; class DroppedFrameCounter; +class EventLatencyTracker; +class FrameSequenceTrackerCollection; class LatencyUkmReporter; struct GlobalMetricsTrackers { - DroppedFrameCounter* dropped_frame_counter = nullptr; - LatencyUkmReporter* latency_ukm_reporter = nullptr; - FrameSequenceTrackerCollection* frame_sequence_trackers = nullptr; + raw_ptr<DroppedFrameCounter> dropped_frame_counter = nullptr; + raw_ptr<LatencyUkmReporter> latency_ukm_reporter = nullptr; + raw_ptr<FrameSequenceTrackerCollection> frame_sequence_trackers = nullptr; + raw_ptr<EventLatencyTracker> event_latency_tracker = nullptr; }; // This is used for tracing and reporting the duration of pipeline stages within @@ -121,12 +123,13 @@ class CC_EXPORT CompositorFrameReporter { kAnimate = 1, kStyleUpdate = 2, kLayoutUpdate = 3, - kPrepaint = 4, - kCompositingInputs = 5, - kPaint = 6, - kCompositeCommit = 7, - kUpdateLayers = 8, - kBeginMainSentToStarted = 9, + kAccessibility = 4, + kPrepaint = 5, + kCompositingInputs = 6, + kPaint = 7, + kCompositeCommit = 8, + kUpdateLayers = 9, + kBeginMainSentToStarted = 10, kBreakdownCount }; @@ -159,7 +162,7 @@ class CC_EXPORT CompositorFrameReporter { base::TimeDelta GetLatency() const; private: - const ProcessedBlinkBreakdown* owner_; + raw_ptr<const ProcessedBlinkBreakdown> owner_; size_t index_ = 0; }; @@ -197,7 +200,7 @@ class CC_EXPORT CompositorFrameReporter { base::TimeDelta GetDuration() const; private: - const ProcessedVizBreakdown* owner_; + raw_ptr<const ProcessedVizBreakdown> owner_; const bool skip_swap_start_to_swap_end_; size_t index_ = 0; @@ -228,7 +231,7 @@ class CC_EXPORT CompositorFrameReporter { CompositorFrameReporter(const ActiveTrackers& active_trackers, const viz::BeginFrameArgs& args, - bool should_report_metrics, + bool should_report_histograms, SmoothThread smooth_thread, FrameInfo::SmoothEffectDrivingThread scrolling_thread, int layer_tree_host_id, @@ -269,6 +272,8 @@ class CC_EXPORT CompositorFrameReporter { void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown); void AddEventsMetrics(EventMetrics::List events_metrics); + + // Erase and return all EventMetrics objects from our list. EventMetrics::List TakeEventsMetrics(); size_t stage_history_size_for_testing() const { @@ -350,7 +355,7 @@ class CC_EXPORT CompositorFrameReporter { void TerminateReporter(); void EndCurrentStage(base::TimeTicks end_time); - void ReportCompositorLatencyHistograms() const; + void ReportCompositorLatencyMetrics() const; void ReportStageHistogramWithBreakdown( const StageData& stage, FrameSequenceTrackerType frame_sequence_tracker_type = @@ -366,7 +371,7 @@ class CC_EXPORT CompositorFrameReporter { absl::optional<BlinkBreakdown> blink_breakdown, base::TimeDelta time_delta) const; - void ReportEventLatencyHistograms() const; + void ReportEventLatencyMetrics() const; void ReportCompositorLatencyTraceEvents(const FrameInfo& info) const; void ReportEventLatencyTraceEvents() const; @@ -389,7 +394,13 @@ class CC_EXPORT CompositorFrameReporter { base::WeakPtr<CompositorFrameReporter> GetWeakPtr(); - const bool should_report_metrics_; + // Erase and return only the EventMetrics objects which depend on main thread + // updates (see comments on EventMetrics::requires_main_thread_update_). + EventMetrics::List TakeMainBlockedEventsMetrics(); + + // Whether UMA histograms should be reported or not. + const bool should_report_histograms_; + const viz::BeginFrameArgs args_; StageData current_stage_; diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.cc b/chromium/cc/metrics/compositor_frame_reporting_controller.cc index fbf02b198a3..c40ffcee3b5 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller.cc +++ b/chromium/cc/metrics/compositor_frame_reporting_controller.cc @@ -26,12 +26,17 @@ constexpr char kTraceCategory[] = "cc,benchmark"; } // namespace CompositorFrameReportingController::CompositorFrameReportingController( - bool should_report_metrics, + bool should_report_histograms, + bool should_report_ukm, int layer_tree_host_id) - : should_report_metrics_(should_report_metrics), + : should_report_histograms_(should_report_histograms), layer_tree_host_id_(layer_tree_host_id), latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()) { - global_trackers_.latency_ukm_reporter = latency_ukm_reporter_.get(); + if (should_report_ukm) { + // UKM metrics should be reported if and only if `latency_ukm_reporter` is + // set on `global_trackers_`. + global_trackers_.latency_ukm_reporter = latency_ukm_reporter_.get(); + } } CompositorFrameReportingController::~CompositorFrameReportingController() { @@ -107,7 +112,7 @@ void CompositorFrameReportingController::WillBeginImplFrame( } } auto reporter = std::make_unique<CompositorFrameReporter>( - active_trackers_, args, should_report_metrics_, GetSmoothThread(), + active_trackers_, args, should_report_histograms_, GetSmoothThread(), scrolling_thread_, layer_tree_host_id_, global_trackers_); reporter->set_tick_clock(tick_clock_); reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame, @@ -145,7 +150,7 @@ void CompositorFrameReportingController::WillBeginMainFrame( smooth_thread = last_started_compositor_frame_.smooth_thread; } auto reporter = std::make_unique<CompositorFrameReporter>( - active_trackers, args, should_report_metrics_, smooth_thread, + active_trackers, args, should_report_histograms_, smooth_thread, scrolling_thread, layer_tree_host_id_, global_trackers_); reporter->set_tick_clock(tick_clock_); reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now()); @@ -729,7 +734,7 @@ void CompositorFrameReportingController::CreateReportersForDroppedFrames( // start time, but they were skipped and history of scrolling thread might // change in the diff of start time and report time. auto reporter = std::make_unique<CompositorFrameReporter>( - active_trackers_, args, should_report_metrics_, + active_trackers_, args, should_report_histograms_, GetSmoothThreadAtTime(timestamp), FrameInfo::SmoothEffectDrivingThread::kUnknown, layer_tree_host_id_, global_trackers_); diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.h b/chromium/cc/metrics/compositor_frame_reporting_controller.h index ee9cfff939a..3d1640c395c 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller.h +++ b/chromium/cc/metrics/compositor_frame_reporting_controller.h @@ -24,6 +24,7 @@ struct FrameTimingDetails; namespace cc { class DroppedFrameCounter; +class EventLatencyTracker; class UkmManager; struct BeginMainFrameMetrics; struct FrameInfo; @@ -45,7 +46,8 @@ class CC_EXPORT CompositorFrameReportingController { kNumPipelineStages }; - CompositorFrameReportingController(bool should_report_metrics, + CompositorFrameReportingController(bool should_report_histograms, + bool should_report_ukm, int layer_tree_host_id); virtual ~CompositorFrameReportingController(); @@ -108,6 +110,10 @@ class CC_EXPORT CompositorFrameReportingController { global_trackers_.frame_sequence_trackers = frame_sequence_trackers; } + void set_event_latency_tracker(EventLatencyTracker* event_latency_tracker) { + global_trackers_.event_latency_tracker = event_latency_tracker; + } + void BeginMainFrameStarted(base::TimeTicks begin_main_frame_start_time) { begin_main_frame_start_time_ = begin_main_frame_start_time; } @@ -166,7 +172,7 @@ class CC_EXPORT CompositorFrameReportingController { void AddSortedFrame(const viz::BeginFrameArgs& args, const FrameInfo& frame_info); - const bool should_report_metrics_; + const bool should_report_histograms_; const int layer_tree_host_id_; viz::BeginFrameId last_submitted_frame_id_; diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 524f144dbac..c831d790240 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc @@ -34,7 +34,8 @@ class TestCompositorFrameReportingController : public CompositorFrameReportingController { public: TestCompositorFrameReportingController() - : CompositorFrameReportingController(/*should_report_metrics=*/true, + : CompositorFrameReportingController(/*should_report_histograms=*/true, + /*should_report_ukm=*/false, /*layer_tree_host_id=*/1) {} TestCompositorFrameReportingController( @@ -1332,6 +1333,77 @@ TEST_F(CompositorFrameReportingControllerTest, } } +TEST_F(CompositorFrameReportingControllerTest, + EventLatencyMainRepaintedScroll) { + base::HistogramTester histogram_tester; + + // Set up two EventMetrics objects. + std::unique_ptr<EventMetrics> metrics_1 = CreateScrollUpdateEventMetrics( + false /* is_inertial */, + ScrollUpdateEventMetrics::ScrollUpdateType::kStarted); + metrics_1->set_requires_main_thread_update(); + base::TimeTicks start_time_1 = metrics_1->GetDispatchStageTimestamp( + EventMetrics::DispatchStage::kGenerated); + + // The second EventMetrics does not have set_requires_main_thread_update(). + // (It's not very realistic for the same scroll gesture to produce two events + // with differing values for this bit, but let's test both conditions here.) + std::unique_ptr<EventMetrics> metrics_2 = CreateScrollUpdateEventMetrics( + false /* is_inertial */, + ScrollUpdateEventMetrics::ScrollUpdateType::kContinued); + base::TimeTicks start_time_2 = metrics_2->GetDispatchStageTimestamp( + EventMetrics::DispatchStage::kGenerated); + + // Simulate a frame getting stuck in the main thread. + SimulateBeginImplFrame(); + SimulateBeginMainFrame(); + reporting_controller_.OnFinishImplFrame(current_id_); + + // Submit a partial update with our events from the compositor thread. + EventMetrics::List metrics_list; + metrics_list.push_back(std::move(metrics_1)); + metrics_list.push_back(std::move(metrics_2)); + reporting_controller_.DidSubmitCompositorFrame( + *current_token_, AdvanceNowByMs(10), current_id_, {}, + {{}, std::move(metrics_list)}, + /*has_missing_content=*/false); + + // Present the partial update. + viz::FrameTimingDetails details_1 = {}; + details_1.presentation_feedback.timestamp = AdvanceNowByMs(10); + reporting_controller_.DidPresentCompositorFrame(*current_token_, details_1); + + // Let the main thread finish its work. + SimulateCommit(nullptr); + SimulateActivate(); + + // Submit the final update. + SimulateBeginImplFrame(); + reporting_controller_.OnFinishImplFrame(current_id_); + SimulateSubmitCompositorFrame({}); + + // Present the final update. + viz::FrameTimingDetails details_2 = {}; + details_2.presentation_feedback.timestamp = AdvanceNowByMs(10); + reporting_controller_.DidPresentCompositorFrame(*current_token_, details_2); + + // metrics_1 has requires_main_thread_update(), so its latency is based on the + // final-update presentation (details_2). + base::TimeDelta expected_latency_1 = + details_2.presentation_feedback.timestamp - start_time_1; + histogram_tester.ExpectBucketCount( + "EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency", + expected_latency_1.InMicroseconds(), 1); + + // metrics_2 did NOT have requires_main_thread_update(), so its latency is + // based on the partial-update presentation (details_1). + base::TimeDelta expected_latency_2 = + details_1.presentation_feedback.timestamp - start_time_2; + histogram_tester.ExpectBucketCount( + "EventLatency.GestureScrollUpdate.Wheel.TotalLatency", + expected_latency_2.InMicroseconds(), 1); +} + // Tests that EventLatency total latency histograms are reported properly for // pinch events when a frame is presented to the user. TEST_F(CompositorFrameReportingControllerTest, diff --git a/chromium/cc/metrics/compositor_timing_history.cc b/chromium/cc/metrics/compositor_timing_history.cc index 1eb6fe1645c..a9c16c24319 100644 --- a/chromium/cc/metrics/compositor_timing_history.cc +++ b/chromium/cc/metrics/compositor_timing_history.cc @@ -442,7 +442,6 @@ CompositorTimingHistory::CompositorTimingHistory( : using_synchronous_renderer_compositor_( using_synchronous_renderer_compositor), enabled_(false), - did_send_begin_main_frame_(false), compositor_drawing_continuously_(false), begin_main_frame_queue_duration_history_(kDurationHistorySize), begin_main_frame_queue_duration_critical_history_(kDurationHistorySize), @@ -466,7 +465,6 @@ CompositorTimingHistory::CompositorTimingHistory( bmf_queue_to_activate_critical_history_(kDurationHistorySize), bmf_queue_to_activate_critical_percentile_( BeginMainFrameQueueToActivateCriticalPercentile()), - begin_main_frame_on_critical_path_(false), uma_reporter_(CreateUMAReporter(uma_category)), rendering_stats_instrumentation_(rendering_stats_instrumentation) {} @@ -598,8 +596,6 @@ void CompositorTimingHistory::WillBeginImplFrame( if (frame_type == viz::BeginFrameArgs::NORMAL) uma_reporter_->AddBeginImplFrameLatency(now - frame_time); - - did_send_begin_main_frame_ = false; } void CompositorTimingHistory::WillFinishImplFrame(bool needs_redraw) { @@ -617,8 +613,6 @@ void CompositorTimingHistory::WillBeginMainFrame( begin_main_frame_on_critical_path_ = args.on_critical_path; begin_main_frame_sent_time_ = Now(); - - did_send_begin_main_frame_ = true; } void CompositorTimingHistory::BeginMainFrameStarted( @@ -635,18 +629,20 @@ void CompositorTimingHistory::BeginMainFrameAborted() { void CompositorTimingHistory::NotifyReadyToCommit() { DCHECK_NE(begin_main_frame_start_time_, base::TimeTicks()); + base::TimeTicks begin_main_frame_end_time = Now(); + base::TimeDelta begin_main_frame_queue_duration = + begin_main_frame_start_time_ - begin_main_frame_sent_time_; begin_main_frame_start_to_ready_to_commit_duration_history_.InsertSample( - Now() - begin_main_frame_start_time_); + begin_main_frame_end_time - begin_main_frame_start_time_); if (duration_estimates_enabled_) { - bmf_start_to_activate_duration_ = Now() - begin_main_frame_start_time_; if (begin_main_frame_on_critical_path_) { bmf_start_to_ready_to_commit_critical_history_.InsertSample( - (Now() - begin_main_frame_start_time_) + - begin_main_frame_queue_duration_); + (begin_main_frame_end_time - begin_main_frame_start_time_) + + begin_main_frame_queue_duration); } else { bmf_start_to_ready_to_commit_not_critical_history_.InsertSample( - (Now() - begin_main_frame_start_time_) + - begin_main_frame_queue_duration_); + (begin_main_frame_end_time - begin_main_frame_start_time_) + + begin_main_frame_queue_duration); } } } @@ -660,17 +656,18 @@ void CompositorTimingHistory::DidCommit() { DCHECK_EQ(pending_tree_creation_time_, base::TimeTicks()); DCHECK_NE(commit_start_time_, base::TimeTicks()); - base::TimeTicks begin_main_frame_end_time = Now(); - DidBeginMainFrame(begin_main_frame_end_time); - commit_duration_history_.InsertSample(begin_main_frame_end_time - - commit_start_time_); - + base::TimeTicks commit_end_time = Now(); if (enabled_ && duration_estimates_enabled_) { - bmf_start_to_activate_duration_ += - begin_main_frame_end_time - commit_start_time_; + pending_tree_on_critical_path_ = begin_main_frame_on_critical_path_; + bmf_start_to_ready_to_activate_duration_ = + commit_end_time - begin_main_frame_start_time_; } + DidBeginMainFrame(commit_end_time); + commit_duration_history_.InsertSample(commit_end_time - commit_start_time_); + pending_tree_is_impl_side_ = false; - pending_tree_creation_time_ = begin_main_frame_end_time; + pending_tree_creation_time_ = commit_end_time; + pending_tree_bmf_queue_duration_ = begin_main_frame_queue_duration_; } void CompositorTimingHistory::DidBeginMainFrame( @@ -718,6 +715,8 @@ void CompositorTimingHistory::WillInvalidateOnImplSide() { DCHECK_EQ(pending_tree_creation_time_, base::TimeTicks()); pending_tree_is_impl_side_ = true; + pending_tree_on_critical_path_ = false; + pending_tree_bmf_queue_duration_ = base::TimeDelta(); pending_tree_creation_time_ = base::TimeTicks::Now(); } @@ -765,7 +764,7 @@ void CompositorTimingHistory::ReadyToActivate() { commit_to_ready_to_activate_duration_history_.InsertSample( time_since_commit); if (duration_estimates_enabled_) - bmf_start_to_activate_duration_ += time_since_commit; + bmf_start_to_ready_to_activate_duration_ += time_since_commit; } } } @@ -777,25 +776,30 @@ void CompositorTimingHistory::WillActivate() { pending_tree_is_impl_side_ = false; pending_tree_creation_time_ = base::TimeTicks(); - pending_tree_ready_to_activate_time_ = base::TimeTicks(); } void CompositorTimingHistory::DidActivate() { DCHECK_NE(base::TimeTicks(), activate_start_time_); - base::TimeDelta activate_duration = Now() - activate_start_time_; + base::TimeTicks activate_end_time = Now(); + base::TimeDelta activate_duration = activate_end_time - activate_start_time_; if (enabled_) { activate_duration_history_.InsertSample(activate_duration); if (duration_estimates_enabled_) { - if (begin_main_frame_on_critical_path_) { + if (pending_tree_on_critical_path_) { + base::TimeDelta time_since_ready_to_activate = + activate_end_time - pending_tree_ready_to_activate_time_; + DCHECK_NE(pending_tree_bmf_queue_duration_, base::TimeDelta()); bmf_queue_to_activate_critical_history_.InsertSample( - bmf_start_to_activate_duration_ + activate_duration + - begin_main_frame_queue_duration_); + bmf_start_to_ready_to_activate_duration_ + + time_since_ready_to_activate + pending_tree_bmf_queue_duration_); } + bmf_start_to_ready_to_activate_duration_ = base::TimeDelta(); } } + pending_tree_ready_to_activate_time_ = base::TimeTicks(); activate_start_time_ = base::TimeTicks(); } diff --git a/chromium/cc/metrics/compositor_timing_history.h b/chromium/cc/metrics/compositor_timing_history.h index d8ad8df66a1..83bd3475a2e 100644 --- a/chromium/cc/metrics/compositor_timing_history.h +++ b/chromium/cc/metrics/compositor_timing_history.h @@ -112,7 +112,6 @@ class CC_EXPORT CompositorTimingHistory { bool enabled_; // Used to calculate frame rates of Main and Impl threads. - bool did_send_begin_main_frame_; bool compositor_drawing_continuously_; base::TimeTicks new_active_tree_draw_end_time_prev_; base::TimeTicks draw_end_time_prev_; @@ -142,10 +141,18 @@ class CC_EXPORT CompositorTimingHistory { RollingTimeDeltaHistory bmf_queue_to_activate_critical_history_; double bmf_queue_to_activate_critical_percentile_; + // The time between when BMF was posted to the main thread task queue, and the + // timestamp taken on the main thread when the BMF started running. base::TimeDelta begin_main_frame_queue_duration_; - base::TimeDelta bmf_start_to_activate_duration_; - - bool begin_main_frame_on_critical_path_; + // The value of begin_main_frame_queue_duration_ that was measured for the + // pending tree. + base::TimeDelta pending_tree_bmf_queue_duration_; + // The time between when BMF was posted to the main thread task queue, and + // when the result of the BMF finished activation. + base::TimeDelta bmf_start_to_ready_to_activate_duration_; + + bool begin_main_frame_on_critical_path_ = false; + bool pending_tree_on_critical_path_ = false; base::TimeTicks begin_main_frame_sent_time_; base::TimeTicks begin_main_frame_start_time_; base::TimeTicks commit_start_time_; diff --git a/chromium/cc/metrics/compositor_timing_history_unittest.cc b/chromium/cc/metrics/compositor_timing_history_unittest.cc index ee60812fc35..05b8d895464 100644 --- a/chromium/cc/metrics/compositor_timing_history_unittest.cc +++ b/chromium/cc/metrics/compositor_timing_history_unittest.cc @@ -6,7 +6,9 @@ #include "base/logging.h" #include "base/memory/raw_ptr.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" +#include "cc/base/features.h" #include "cc/debug/rendering_stats_instrumentation.h" #include "cc/metrics/dropped_frame_counter.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,6 +29,19 @@ class TestCompositorTimingHistory : public CompositorTimingHistory { TestCompositorTimingHistory& operator=(const TestCompositorTimingHistory&) = delete; + const RollingTimeDeltaHistory& bmf_start_to_ready_to_commit_critical_history() + const { + return bmf_start_to_ready_to_commit_critical_history_; + } + const RollingTimeDeltaHistory& + bmf_start_to_ready_to_commit_not_critical_history() const { + return bmf_start_to_ready_to_commit_not_critical_history_; + } + const RollingTimeDeltaHistory& bmf_queue_to_activate_critical_history() + const { + return bmf_queue_to_activate_critical_history_; + } + protected: base::TimeTicks Now() const override; @@ -36,7 +51,8 @@ class TestCompositorTimingHistory : public CompositorTimingHistory { class CompositorTimingHistoryTest : public testing::Test { public: CompositorTimingHistoryTest() - : rendering_stats_(RenderingStatsInstrumentation::Create()), + : feature_list(features::kDurationEstimatesInCompositorTimingHistory), + rendering_stats_(RenderingStatsInstrumentation::Create()), timing_history_(this, rendering_stats_.get()) { AdvanceNowBy(base::Milliseconds(1)); timing_history_.SetRecordingEnabled(true); @@ -47,6 +63,7 @@ class CompositorTimingHistoryTest : public testing::Test { base::TimeTicks Now() { return now_; } protected: + base::test::ScopedFeatureList feature_list; std::unique_ptr<RenderingStatsInstrumentation> rendering_stats_; TestCompositorTimingHistory timing_history_; base::TimeTicks now_; @@ -276,5 +293,128 @@ TEST_F(CompositorTimingHistoryTest, BeginMainFrames_NewCriticalSlower) { timing_history_.BeginMainFrameQueueDurationNotCriticalEstimate()); } +TEST_F(CompositorTimingHistoryTest, BeginMainFrameToActivateDuration) { + viz::BeginFrameArgs args_ = GetFakeBeginFrameArg(true); + timing_history_.WillBeginMainFrame(args_); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.BeginMainFrameStarted(Now()); + AdvanceNowBy(base::Milliseconds(2)); + timing_history_.NotifyReadyToCommit(); + AdvanceNowBy(base::Milliseconds(3)); + timing_history_.WillCommit(); + AdvanceNowBy(base::Milliseconds(4)); + timing_history_.DidCommit(); + AdvanceNowBy(base::Milliseconds(5)); + timing_history_.ReadyToActivate(); + AdvanceNowBy(base::Milliseconds(6)); + timing_history_.WillActivate(); + AdvanceNowBy(base::Milliseconds(7)); + timing_history_.DidActivate(); + EXPECT_EQ( + 1u, + timing_history_.bmf_queue_to_activate_critical_history().sample_count()); + EXPECT_EQ( + base::Milliseconds(1 + 2 + 3 + 4 + 5 + 6 + 7), + timing_history_.bmf_queue_to_activate_critical_history().Percentile(0.)); +} + +TEST_F(CompositorTimingHistoryTest, OnCriticalPath) { + viz::BeginFrameArgs bmf_args = GetFakeBeginFrameArg(true); + timing_history_.WillBeginMainFrame(bmf_args); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.BeginMainFrameStarted(Now()); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.NotifyReadyToCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.WillCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.DidCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.ReadyToActivate(); + AdvanceNowBy(base::Milliseconds(1)); + + // The previous frame should still be treated as on_critical_path + bmf_args = GetFakeBeginFrameArg(false); + timing_history_.WillBeginMainFrame(bmf_args); + + timing_history_.WillActivate(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.DidActivate(); + + EXPECT_EQ(1u, timing_history_.bmf_start_to_ready_to_commit_critical_history() + .sample_count()); + EXPECT_EQ(base::Milliseconds(2), + timing_history_.bmf_start_to_ready_to_commit_critical_history() + .Percentile(0.)); + EXPECT_EQ(0u, + timing_history_.bmf_start_to_ready_to_commit_not_critical_history() + .sample_count()); + EXPECT_EQ( + 1u, + timing_history_.bmf_queue_to_activate_critical_history().sample_count()); + EXPECT_EQ( + base::Milliseconds(7), + timing_history_.bmf_queue_to_activate_critical_history().Percentile(0.)); + + timing_history_.BeginMainFrameStarted(Now()); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.NotifyReadyToCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.WillCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.DidCommit(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.ReadyToActivate(); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.WillActivate(); + AdvanceNowBy(base::Milliseconds(1)); + + // The previous frame should still be treated as not on_critical_path + bmf_args = GetFakeBeginFrameArg(true); + timing_history_.WillBeginMainFrame(bmf_args); + timing_history_.DidActivate(); + + EXPECT_EQ(1u, timing_history_.bmf_start_to_ready_to_commit_critical_history() + .sample_count()); + EXPECT_EQ(1u, + timing_history_.bmf_start_to_ready_to_commit_not_critical_history() + .sample_count()); + EXPECT_EQ( + 1u, + timing_history_.bmf_queue_to_activate_critical_history().sample_count()); +} + +TEST_F(CompositorTimingHistoryTest, BeginMainFrameQueueDuration) { + viz::BeginFrameArgs args_ = GetFakeBeginFrameArg(true); + timing_history_.WillBeginMainFrame(args_); + AdvanceNowBy(base::Milliseconds(1)); + timing_history_.BeginMainFrameStarted(Now()); + AdvanceNowBy(base::Milliseconds(2)); + timing_history_.NotifyReadyToCommit(); + AdvanceNowBy(base::Milliseconds(3)); + timing_history_.WillCommit(); + AdvanceNowBy(base::Milliseconds(4)); + timing_history_.DidCommit(); + AdvanceNowBy(base::Milliseconds(5)); + timing_history_.ReadyToActivate(); + AdvanceNowBy(base::Milliseconds(6)); + timing_history_.WillBeginMainFrame(args_); + AdvanceNowBy(base::Milliseconds(7)); + timing_history_.BeginMainFrameStarted(Now()); + AdvanceNowBy(base::Milliseconds(8)); + timing_history_.BeginMainFrameAborted(); + AdvanceNowBy(base::Milliseconds(9)); + timing_history_.WillActivate(); + AdvanceNowBy(base::Milliseconds(10)); + timing_history_.DidActivate(); + EXPECT_EQ( + 1u, + timing_history_.bmf_queue_to_activate_critical_history().sample_count()); + // The bmf queueing duration should be 1ms, not the 7ms for the aborted frame. + EXPECT_EQ( + base::Milliseconds(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10), + timing_history_.bmf_queue_to_activate_critical_history().Percentile(0.)); +} + } // namespace } // namespace cc diff --git a/chromium/cc/metrics/custom_metrics_recorder.cc b/chromium/cc/metrics/custom_metrics_recorder.cc new file mode 100644 index 00000000000..5b25f11401a --- /dev/null +++ b/chromium/cc/metrics/custom_metrics_recorder.cc @@ -0,0 +1,31 @@ +// Copyright 2020 The Chromium 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/metrics/custom_metrics_recorder.h" + +#include "base/check_op.h" + +namespace cc { +namespace { + +CustomMetricRecorder* g_instance = nullptr; + +} // namespace + +// static +CustomMetricRecorder* CustomMetricRecorder::Get() { + return g_instance; +} + +CustomMetricRecorder::CustomMetricRecorder() { + DCHECK_EQ(nullptr, g_instance); + g_instance = this; +} + +CustomMetricRecorder::~CustomMetricRecorder() { + DCHECK_EQ(this, g_instance); + g_instance = nullptr; +} + +} // namespace cc diff --git a/chromium/cc/metrics/custom_metrics_recorder.h b/chromium/cc/metrics/custom_metrics_recorder.h new file mode 100644 index 00000000000..fa4f8ad36a6 --- /dev/null +++ b/chromium/cc/metrics/custom_metrics_recorder.h @@ -0,0 +1,27 @@ +// Copyright 2022 The Chromium 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_METRICS_CUSTOM_METRICS_RECORDER_H_ +#define CC_METRICS_CUSTOM_METRICS_RECORDER_H_ + +#include "cc/cc_export.h" + +namespace cc { + +// Customize cc metric recording. E.g. reporting metrics under different names. +class CC_EXPORT CustomMetricRecorder { + public: + static CustomMetricRecorder* Get(); + + // Invoked to report "PercentDroppedFrames_1sWindow". + virtual void ReportPercentDroppedFramesInOneSecoundWindow(double percent) = 0; + + protected: + CustomMetricRecorder(); + virtual ~CustomMetricRecorder(); +}; + +} // namespace cc + +#endif // CC_METRICS_CUSTOM_METRICS_RECORDER_H_ diff --git a/chromium/cc/metrics/dropped_frame_counter.cc b/chromium/cc/metrics/dropped_frame_counter.cc index e7fd9cffec1..3ad8364c7a0 100644 --- a/chromium/cc/metrics/dropped_frame_counter.cc +++ b/chromium/cc/metrics/dropped_frame_counter.cc @@ -15,6 +15,7 @@ #include "base/trace_event/trace_event.h" #include "build/chromeos_buildflags.h" #include "cc/base/features.h" +#include "cc/metrics/custom_metrics_recorder.h" #include "cc/metrics/frame_sorter.h" #include "cc/metrics/total_frame_counter.h" #include "cc/metrics/ukm_smoothness_data.h" @@ -397,10 +398,13 @@ void DroppedFrameCounter::ReportFrames() { void DroppedFrameCounter::ReportFramesForUI() { DCHECK(report_for_ui_); -#if BUILDFLAG(IS_CHROMEOS_ASH) - UMA_HISTOGRAM_PERCENTAGE("Ash.Smoothness.PercentDroppedFrames_1sWindow", - sliding_window_current_percent_dropped_); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) + + auto* recorder = CustomMetricRecorder::Get(); + if (!recorder) + return; + + recorder->ReportPercentDroppedFramesInOneSecoundWindow( + sliding_window_current_percent_dropped_); } double DroppedFrameCounter::GetMostRecentAverageSmoothness() const { diff --git a/chromium/cc/metrics/dropped_frame_counter_unittest.cc b/chromium/cc/metrics/dropped_frame_counter_unittest.cc index cc48999db8e..92167651cc8 100644 --- a/chromium/cc/metrics/dropped_frame_counter_unittest.cc +++ b/chromium/cc/metrics/dropped_frame_counter_unittest.cc @@ -9,10 +9,10 @@ #include "base/memory/raw_ptr.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" -#include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" #include "build/chromeos_buildflags.h" #include "cc/animation/animation_host.h" +#include "cc/metrics/custom_metrics_recorder.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_frame_info.h" #include "cc/test/fake_picture_layer.h" @@ -29,6 +29,31 @@ FrameInfo CreateStubFrameInfo(bool is_dropped) { : FrameInfo::FrameFinalState::kPresentedAll); } +class TestCustomMetricsRecorder : public CustomMetricRecorder { + public: + TestCustomMetricsRecorder() = default; + ~TestCustomMetricsRecorder() override = default; + + // CustomMetricRecorder: + void ReportPercentDroppedFramesInOneSecoundWindow( + double percentage) override { + ++percent_dropped_frames_count_; + last_percent_dropped_frames_ = percentage; + } + + int percent_dropped_frames_count() const { + return percent_dropped_frames_count_; + } + + double last_percent_dropped_frames() const { + return last_percent_dropped_frames_; + } + + private: + int percent_dropped_frames_count_ = 0; + double last_percent_dropped_frames_ = 0; +}; + class DroppedFrameCounterTestBase : public LayerTreeTest { public: DroppedFrameCounterTestBase() = default; @@ -917,7 +942,6 @@ TEST_F(DroppedFrameCounterTest, WorstSmoothnessTiming) { EXPECT_FLOAT_EQ(MaxPercentDroppedFrameAfter5Sec(), 100); } -#if BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(DroppedFrameCounterTest, ReportForUI) { constexpr auto kInterval = base::Milliseconds(10); constexpr size_t kFps = base::Seconds(1) / kInterval; @@ -927,17 +951,15 @@ TEST_F(DroppedFrameCounterTest, ReportForUI) { SetInterval(kInterval); dropped_frame_counter_.EnableReporForUI(); - base::HistogramTester histogram_tester; + TestCustomMetricsRecorder recorder; // 4 seconds with 20% dropped frames. SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4); // Recorded more than 1 samples of 20% dropped frame percentage. - EXPECT_GE(histogram_tester.GetBucketCount( - "Ash.Smoothness.PercentDroppedFrames_1sWindow", 20), - 1); + EXPECT_GE(recorder.percent_dropped_frames_count(), 1); + EXPECT_EQ(recorder.last_percent_dropped_frames(), 20.0f); } -#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace } // namespace cc diff --git a/chromium/cc/metrics/event_latency_tracing_recorder.cc b/chromium/cc/metrics/event_latency_tracing_recorder.cc index 96586cf52d0..57dce582e1f 100644 --- a/chromium/cc/metrics/event_latency_tracing_recorder.cc +++ b/chromium/cc/metrics/event_latency_tracing_recorder.cc @@ -35,7 +35,7 @@ constexpr const char* GetDispatchBreakdownName( return "RendererCompositorToMain"; default: NOTREACHED(); - return nullptr; + return ""; } case EventMetrics::DispatchStage::kRendererCompositorStarted: DCHECK_EQ(end_stage, @@ -49,7 +49,7 @@ constexpr const char* GetDispatchBreakdownName( return "RendererMainProcessing"; case EventMetrics::DispatchStage::kRendererMainFinished: NOTREACHED(); - return nullptr; + return ""; } } @@ -80,7 +80,7 @@ constexpr const char* GetDispatchToCompositorBreakdownName( return "RendererCompositorFinishedToSubmitCompositorFrame"; default: NOTREACHED(); - return nullptr; + return ""; } case EventMetrics::DispatchStage::kRendererMainFinished: switch (compositor_stage) { @@ -103,11 +103,11 @@ constexpr const char* GetDispatchToCompositorBreakdownName( return "RendererMainFinishedToSubmitCompositorFrame"; default: NOTREACHED(); - return nullptr; + return ""; } default: NOTREACHED(); - return nullptr; + return ""; } } @@ -128,7 +128,7 @@ constexpr const char* GetDispatchToTerminationBreakdownName( return "RendererMainFinishedToTermination"; default: NOTREACHED(); - return nullptr; + return ""; } } @@ -176,8 +176,7 @@ void EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( const std::vector<CompositorFrameReporter::StageData>* stage_history, const CompositorFrameReporter::ProcessedVizBreakdown* viz_breakdown) { DCHECK(event_metrics); - DCHECK(!event_metrics->is_tracing_recorded()); - event_metrics->set_tracing_recorded(); + DCHECK(event_metrics->should_record_tracing()); const base::TimeTicks generated_timestamp = event_metrics->GetDispatchStageTimestamp( @@ -227,68 +226,68 @@ void EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( } if (stage_history) { DCHECK(viz_breakdown); - // Find the first compositor stage that happens after the final dispatch - // stage. + // Find the first compositor stage that starts at the same time or after the + // end of the final event dispatch stage. auto stage_it = std::find_if( stage_history->begin(), stage_history->end(), [dispatch_timestamp](const CompositorFrameReporter::StageData& stage) { - return stage.start_time > dispatch_timestamp; + return stage.start_time >= dispatch_timestamp; }); - // TODO(crbug.com/1079116): Ideally, at least the start time of + // TODO(crbug.com/1330903): Ideally, at least the start time of // SubmitCompositorFrameToPresentationCompositorFrame stage should be - // greater than the final event dispatch timestamp, but apparently, this is - // not always the case (see crbug.com/1093698). For now, skip to the next - // event in such cases. Hopefully, the work to reduce discrepancies between - // the new EventLatency and the old Event.Latency metrics would fix this - // issue. If not, we need to reconsider investigating this issue. - if (stage_it == stage_history->end()) - return; + // greater than or equal to the final event dispatch timestamp, but + // apparently, this is not always the case (see crbug.com/1330903). Skip + // recording compositor stages for now until we investigate the issue. + if (stage_it != stage_history->end()) { + DCHECK(dispatch_stage == + EventMetrics::DispatchStage::kRendererCompositorFinished || + dispatch_stage == + EventMetrics::DispatchStage::kRendererMainFinished); - DCHECK(dispatch_stage == - EventMetrics::DispatchStage::kRendererCompositorFinished || - dispatch_stage == - EventMetrics::DispatchStage::kRendererMainFinished); - - const char* d2c_breakdown_name = GetDispatchToCompositorBreakdownName( - dispatch_stage, stage_it->stage_type); - TRACE_EVENT_BEGIN(kTracingCategory, - perfetto::StaticString{d2c_breakdown_name}, trace_track, - dispatch_timestamp); - TRACE_EVENT_END(kTracingCategory, trace_track, stage_it->start_time); + // Record dispatch-to-compositor stage only if it has non-zero duration. + if (dispatch_timestamp < stage_it->start_time) { + const char* d2c_breakdown_name = GetDispatchToCompositorBreakdownName( + dispatch_stage, stage_it->stage_type); + TRACE_EVENT_BEGIN(kTracingCategory, + perfetto::StaticString{d2c_breakdown_name}, + trace_track, dispatch_timestamp); + TRACE_EVENT_END(kTracingCategory, trace_track, stage_it->start_time); + } - // Compositor stages. - for (; stage_it != stage_history->end(); ++stage_it) { - if (stage_it->start_time >= termination_time) - break; - DCHECK_GE(stage_it->end_time, stage_it->start_time); - if (stage_it->start_time == stage_it->end_time) - continue; - const char* stage_name = - CompositorFrameReporter::GetStageName(stage_it->stage_type); + // Compositor stages. + for (; stage_it != stage_history->end(); ++stage_it) { + if (stage_it->start_time >= termination_time) + break; + DCHECK_GE(stage_it->end_time, stage_it->start_time); + if (stage_it->start_time == stage_it->end_time) + continue; + const char* stage_name = + CompositorFrameReporter::GetStageName(stage_it->stage_type); - TRACE_EVENT_BEGIN(kTracingCategory, perfetto::StaticString{stage_name}, - trace_track, stage_it->start_time); + TRACE_EVENT_BEGIN(kTracingCategory, perfetto::StaticString{stage_name}, + trace_track, stage_it->start_time); - if (stage_it->stage_type == - CompositorFrameReporter::StageType:: - kSubmitCompositorFrameToPresentationCompositorFrame) { - DCHECK(viz_breakdown); - for (auto it = viz_breakdown->CreateIterator(true); it.IsValid(); - it.Advance()) { - base::TimeTicks start_time = it.GetStartTime(); - base::TimeTicks end_time = it.GetEndTime(); - if (start_time >= end_time) - continue; - const char* breakdown_name = - CompositorFrameReporter::GetVizBreakdownName(it.GetBreakdown()); - TRACE_EVENT_BEGIN(kTracingCategory, - perfetto::StaticString{breakdown_name}, trace_track, - start_time); - TRACE_EVENT_END(kTracingCategory, trace_track, end_time); + if (stage_it->stage_type == + CompositorFrameReporter::StageType:: + kSubmitCompositorFrameToPresentationCompositorFrame) { + DCHECK(viz_breakdown); + for (auto it = viz_breakdown->CreateIterator(true); it.IsValid(); + it.Advance()) { + base::TimeTicks start_time = it.GetStartTime(); + base::TimeTicks end_time = it.GetEndTime(); + if (start_time >= end_time) + continue; + const char* breakdown_name = + CompositorFrameReporter::GetVizBreakdownName(it.GetBreakdown()); + TRACE_EVENT_BEGIN(kTracingCategory, + perfetto::StaticString{breakdown_name}, + trace_track, start_time); + TRACE_EVENT_END(kTracingCategory, trace_track, end_time); + } } - } - TRACE_EVENT_END(kTracingCategory, trace_track, stage_it->end_time); + TRACE_EVENT_END(kTracingCategory, trace_track, stage_it->end_time); + } } } else { DCHECK(!viz_breakdown); @@ -300,6 +299,8 @@ void EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( TRACE_EVENT_END(kTracingCategory, trace_track, termination_time); } TRACE_EVENT_END(kTracingCategory, trace_track, termination_time); + + event_metrics->tracing_recorded(); } } // namespace cc diff --git a/chromium/cc/metrics/event_latency_tracker.cc b/chromium/cc/metrics/event_latency_tracker.cc new file mode 100644 index 00000000000..17e4cf4cb01 --- /dev/null +++ b/chromium/cc/metrics/event_latency_tracker.cc @@ -0,0 +1,23 @@ +// Copyright 2022 The Chromium 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/metrics/event_latency_tracker.h" + +namespace cc { + +EventLatencyTracker::LatencyData::LatencyData( + EventMetrics::EventType event_type, + base::TimeDelta total_latency) + : event_type(event_type), total_latency(total_latency) {} + +EventLatencyTracker::LatencyData::~LatencyData() = default; + +EventLatencyTracker::LatencyData::LatencyData(LatencyData&&) = default; +EventLatencyTracker::LatencyData& EventLatencyTracker::LatencyData::operator=( + LatencyData&&) = default; + +EventLatencyTracker::EventLatencyTracker() = default; +EventLatencyTracker::~EventLatencyTracker() = default; + +} // namespace cc diff --git a/chromium/cc/metrics/event_latency_tracker.h b/chromium/cc/metrics/event_latency_tracker.h new file mode 100644 index 00000000000..1d42588c343 --- /dev/null +++ b/chromium/cc/metrics/event_latency_tracker.h @@ -0,0 +1,54 @@ +// Copyright 2022 The Chromium 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_METRICS_EVENT_LATENCY_TRACKER_H_ +#define CC_METRICS_EVENT_LATENCY_TRACKER_H_ + +#include <vector> + +#include "base/time/time.h" +#include "cc/cc_export.h" +#include "cc/metrics/event_metrics.h" +#include "third_party/abseil-cpp/absl/types/variant.h" + +namespace cc { + +// Used by `CompositorFrameReporter` to report event latency information back to +// `LayerTreeHostImpl` and eventually to UI compositor. +class CC_EXPORT EventLatencyTracker { + public: + struct CC_EXPORT LatencyData { + LatencyData(EventMetrics::EventType event_type, + base::TimeDelta total_latency); + ~LatencyData(); + + LatencyData(const LatencyData&) = delete; + LatencyData& operator=(const LatencyData&) = delete; + + LatencyData(LatencyData&&); + LatencyData& operator=(LatencyData&&); + + EventMetrics::EventType event_type; + base::TimeDelta total_latency; + + // Type of the input device if the event is a scroll or a pinch event. + absl::variant<absl::monostate, + ScrollEventMetrics::ScrollType, + PinchEventMetrics::PinchType> + input_type; + }; + + EventLatencyTracker(); + virtual ~EventLatencyTracker(); + + EventLatencyTracker(const EventLatencyTracker&) = delete; + EventLatencyTracker& operator=(const EventLatencyTracker&) = delete; + + // Called every time a frame has latency metrics to report for events. + virtual void ReportEventLatency(std::vector<LatencyData> latencies) = 0; +}; + +} // namespace cc + +#endif // CC_METRICS_EVENT_LATENCY_TRACKER_H_ diff --git a/chromium/cc/metrics/event_metrics.cc b/chromium/cc/metrics/event_metrics.cc index a2ad67a8be9..aff7043c15f 100644 --- a/chromium/cc/metrics/event_metrics.cc +++ b/chromium/cc/metrics/event_metrics.cc @@ -255,12 +255,14 @@ EventMetrics::EventMetrics(EventType type, } EventMetrics::EventMetrics(const EventMetrics& other) - : type_(other.type_), tick_clock_(other.tick_clock_) { + : type_(other.type_), + tick_clock_(other.tick_clock_), + should_record_tracing_(false) { CopyTimestampsFrom(other, DispatchStage::kMaxValue); } EventMetrics::~EventMetrics() { - if (!is_tracing_recorded()) { + if (should_record_tracing()) { EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( this, base::TimeTicks::Now(), nullptr, nullptr); } @@ -428,7 +430,7 @@ ScrollEventMetrics::ScrollEventMetrics(EventType type, ScrollEventMetrics::ScrollEventMetrics(const ScrollEventMetrics&) = default; ScrollEventMetrics::~ScrollEventMetrics() { - if (!is_tracing_recorded()) { + if (should_record_tracing()) { EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( this, base::TimeTicks::Now(), nullptr, nullptr); } @@ -561,7 +563,7 @@ ScrollUpdateEventMetrics::ScrollUpdateEventMetrics( const ScrollUpdateEventMetrics&) = default; ScrollUpdateEventMetrics::~ScrollUpdateEventMetrics() { - if (!is_tracing_recorded()) { + if (should_record_tracing()) { EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( this, base::TimeTicks::Now(), nullptr, nullptr); } @@ -648,7 +650,7 @@ PinchEventMetrics::PinchEventMetrics(EventType type, PinchEventMetrics::PinchEventMetrics(const PinchEventMetrics&) = default; PinchEventMetrics::~PinchEventMetrics() { - if (!is_tracing_recorded()) { + if (should_record_tracing()) { EventLatencyTracingRecorder::RecordEventLatencyTraceEvent( this, base::TimeTicks::Now(), nullptr, nullptr); } diff --git a/chromium/cc/metrics/event_metrics.h b/chromium/cc/metrics/event_metrics.h index 6cd48a69f32..b8c43eab201 100644 --- a/chromium/cc/metrics/event_metrics.h +++ b/chromium/cc/metrics/event_metrics.h @@ -126,16 +126,29 @@ class CC_EXPORT EventMetrics { virtual std::unique_ptr<EventMetrics> Clone() const; - bool is_tracing_recorded() const { return is_tracing_recorded_; } - void set_tracing_recorded() { - DCHECK(!is_tracing_recorded_); - is_tracing_recorded_ = true; + bool should_record_tracing() const { return should_record_tracing_; } + void tracing_recorded() { + DCHECK(should_record_tracing_); + should_record_tracing_ = false; + } + + bool requires_main_thread_update() const { + return requires_main_thread_update_; + } + void set_requires_main_thread_update() { + DCHECK(!requires_main_thread_update_); + requires_main_thread_update_ = true; } protected: EventMetrics(EventType type, base::TimeTicks timestamp, const base::TickClock* tick_clock); + + // Creates a clone of `other` that might be used in creating `EventMetrics` + // objects for some injected events. Since this object itself does not + // directly correspond to an event, it won't be used in recording trace + // events. EventMetrics(const EventMetrics& other); // Copy timestamps of dispatch stages (up to and including @@ -163,7 +176,17 @@ class CC_EXPORT EventMetrics { dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kMaxValue) + 1]; - bool is_tracing_recorded_ = false; + // Determines whether a tracing event should be recorded for this object or + // not. This is `true` by default and set to `false` after a tracing event is + // recorded to avoid multiple recordings. Also, it is `false` for cloned + // objects as they are not meant to be recorded in tracings. + bool should_record_tracing_ = true; + + // This is set on an EventMetrics object that comes from the impl thread, if + // the visual update from the event requires the main thread. Currently used + // for GestureScrollUpdate with scroll unification, when the scroller isn't + // composited or has main-thread scrolling reasons on the ScrollNode. + bool requires_main_thread_update_ = false; }; class CC_EXPORT ScrollEventMetrics : public EventMetrics { diff --git a/chromium/cc/metrics/frame_info.cc b/chromium/cc/metrics/frame_info.cc index 94fcef7a2db..003cc67a9cb 100644 --- a/chromium/cc/metrics/frame_info.cc +++ b/chromium/cc/metrics/frame_info.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/check.h" #include "build/build_config.h" namespace cc { @@ -179,6 +180,10 @@ bool FrameInfo::WasSmoothMainUpdateDropped() const { return false; } +bool FrameInfo::WasSmoothMainUpdateExpected() const { + return final_state != FrameFinalState::kNoUpdateDesired; +} + bool FrameInfo::IsScrollPrioritizeFrameDropped() const { // If any scroll is active the dropped frame for only the scrolling thread is // reported. If no scroll is active then reports if dropped frames is diff --git a/chromium/cc/metrics/frame_info.h b/chromium/cc/metrics/frame_info.h index 1ebdfd87a78..6fbbeb3819b 100644 --- a/chromium/cc/metrics/frame_info.h +++ b/chromium/cc/metrics/frame_info.h @@ -70,6 +70,7 @@ struct CC_EXPORT FrameInfo { // whether the update was part of a smooth sequence. bool WasSmoothCompositorUpdateDropped() const; bool WasSmoothMainUpdateDropped() const; + bool WasSmoothMainUpdateExpected() const; bool IsScrollPrioritizeFrameDropped() const; diff --git a/chromium/cc/metrics/frame_sequence_metrics.cc b/chromium/cc/metrics/frame_sequence_metrics.cc index 1f4c2a5f717..5d3938153e7 100644 --- a/chromium/cc/metrics/frame_sequence_metrics.cc +++ b/chromium/cc/metrics/frame_sequence_metrics.cc @@ -25,6 +25,10 @@ using SmoothEffectDrivingThread = FrameInfo::SmoothEffectDrivingThread; bool ShouldReportForAnimation(FrameSequenceTrackerType sequence_type, SmoothEffectDrivingThread thread_type) { + // kSETMainThreadAnimation and kSETCompositorAnimation sequences are a subset + // of kMainThreadAnimation and kCompositorAnimation sequences. So these are + // excluded from the AllAnimation metric to avoid double counting. + if (sequence_type == FrameSequenceTrackerType::kCompositorAnimation) return thread_type == SmoothEffectDrivingThread::kCompositor; @@ -91,6 +95,13 @@ std::string GetThroughputV2HistogramName(FrameSequenceTrackerType type, FrameSequenceTracker::GetFrameSequenceTrackerTypeName(type)}); } +std::string GetThroughputV3HistogramName(FrameSequenceTrackerType type, + const char* thread_name) { + return base::StrCat( + {"Graphics.Smoothness.PercentDroppedFrames3.", thread_name, ".", + FrameSequenceTracker::GetFrameSequenceTrackerTypeName(type)}); +} + std::string GetMissedDeadlineHistogramName(FrameSequenceTrackerType type, const char* thread_name) { return base::StrCat( @@ -149,11 +160,13 @@ void FrameSequenceMetrics::SetCustomReporter(CustomReporter custom_reporter) { SmoothEffectDrivingThread FrameSequenceMetrics::GetEffectiveThread() const { switch (type_) { case FrameSequenceTrackerType::kCompositorAnimation: + case FrameSequenceTrackerType::kSETCompositorAnimation: case FrameSequenceTrackerType::kPinchZoom: case FrameSequenceTrackerType::kVideo: return SmoothEffectDrivingThread::kCompositor; case FrameSequenceTrackerType::kMainThreadAnimation: + case FrameSequenceTrackerType::kSETMainThreadAnimation: case FrameSequenceTrackerType::kRAF: case FrameSequenceTrackerType::kCanvasAnimation: case FrameSequenceTrackerType::kJSAnimation: @@ -186,6 +199,9 @@ void FrameSequenceMetrics::Merge( v2_.frames_expected += metrics->v2_.frames_expected; v2_.frames_dropped += metrics->v2_.frames_dropped; + v3_.frames_expected += metrics->v3_.frames_expected; + v3_.frames_dropped += metrics->v3_.frames_dropped; + if (jank_reporter_) jank_reporter_->Merge(std::move(metrics->jank_reporter_)); @@ -198,12 +214,14 @@ void FrameSequenceMetrics::Merge( bool FrameSequenceMetrics::HasEnoughDataForReporting() const { return impl_throughput_.frames_expected >= kMinFramesForThroughputMetric || - main_throughput_.frames_expected >= kMinFramesForThroughputMetric; + main_throughput_.frames_expected >= kMinFramesForThroughputMetric || + v2_.frames_expected >= kMinFramesForThroughputMetric || + v3_.frames_expected >= kMinFramesForThroughputMetric; } bool FrameSequenceMetrics::HasDataLeftForReporting() const { - return impl_throughput_.frames_expected > 0 || - main_throughput_.frames_expected > 0; + return impl_throughput_.frames_expected > 0 || v2_.frames_expected > 0 || + main_throughput_.frames_expected > 0 || v3_.frames_expected > 0; } void FrameSequenceMetrics::AdoptTrace(FrameSequenceMetrics* adopt_from) { @@ -263,11 +281,12 @@ void FrameSequenceMetrics::ReportMetrics() { const bool compositor_report = ThroughputData::CanReportHistogram( this, SmoothEffectDrivingThread::kCompositor, impl_throughput_); + const auto thread_type = GetEffectiveThread(); + const bool is_animation = ShouldReportForAnimation(type(), thread_type); + const bool is_interaction = + ShouldReportForInteraction(type(), thread_type, thread_type); + if (v2_.frames_expected >= kMinFramesForThroughputMetric) { - const auto thread_type = GetEffectiveThread(); - const bool is_animation = ShouldReportForAnimation(type(), thread_type); - const bool is_interaction = - ShouldReportForInteraction(type(), thread_type, thread_type); int percent = v2_.frames_expected == 0 ? 0 : std::ceil(100. * v2_.frames_dropped / @@ -298,10 +317,44 @@ void FrameSequenceMetrics::ReportMetrics() { base::LinearHistogram::FactoryGet( GetThroughputV2HistogramName(type(), thread_name), 1, 100, 101, base::HistogramBase::kUmaTargetedHistogramFlag)); - v2_ = {}; } + if (v3_.frames_expected >= kMinFramesForThroughputMetric) { + int percent = v3_.frames_expected == 0 + ? 0 + : std::ceil(100. * v3_.frames_dropped / + static_cast<double>(v3_.frames_expected)); + + if (is_animation) { + UMA_HISTOGRAM_PERCENTAGE( + "Graphics.Smoothness.PercentDroppedFrames3.AllAnimations", percent); + } + if (is_interaction) { + UMA_HISTOGRAM_PERCENTAGE( + "Graphics.Smoothness.PercentDroppedFrames3.AllInteractions", percent); + } + if (is_animation || is_interaction) { + UMA_HISTOGRAM_PERCENTAGE( + "Graphics.Smoothness.PercentDroppedFrames3.AllSequences", percent); + } + + const char* thread_name = + thread_type == SmoothEffectDrivingThread::kCompositor + ? "CompositorThread" + : "MainThread"; + + STATIC_HISTOGRAM_POINTER_GROUP( + GetThroughputV3HistogramName(type(), thread_name), + GetIndexForMetric(thread_type, type_), kMaximumHistogramIndex, + Add(percent), + base::LinearHistogram::FactoryGet( + GetThroughputV3HistogramName(type(), thread_name), 1, 100, 101, + base::HistogramBase::kUmaTargetedHistogramFlag)); + + v3_ = {}; + } + absl::optional<int> impl_throughput_percent_dropped; absl::optional<int> impl_throughput_percent_missed; absl::optional<int> main_throughput_percent_dropped; @@ -465,14 +518,16 @@ bool FrameSequenceMetrics::ThroughputData::CanReportHistogram( const auto sequence_type = metrics->type(); DCHECK_LT(sequence_type, FrameSequenceTrackerType::kMaxType); - // All video frames are compositor thread only. - if (sequence_type == FrameSequenceTrackerType::kVideo && + // All video frames and SET compositor animations are compositor thread only. + if ((sequence_type == FrameSequenceTrackerType::kVideo || + sequence_type == FrameSequenceTrackerType::kSETCompositorAnimation) && thread_type == SmoothEffectDrivingThread::kMain) return false; - // RAF and CanvasAnimation are main thread only. + // RAF, CanvasAnimation and SET main thread animations are main thread only. if ((sequence_type == FrameSequenceTrackerType::kRAF || - sequence_type == FrameSequenceTrackerType::kCanvasAnimation) && + sequence_type == FrameSequenceTrackerType::kCanvasAnimation || + sequence_type == FrameSequenceTrackerType::kSETMainThreadAnimation) && thread_type == SmoothEffectDrivingThread::kCompositor) return false; @@ -485,7 +540,9 @@ bool FrameSequenceMetrics::ThroughputData::CanReportHistogram( return is_animation || IsInteractionType(sequence_type) || sequence_type == FrameSequenceTrackerType::kVideo || sequence_type == FrameSequenceTrackerType::kRAF || - sequence_type == FrameSequenceTrackerType::kCanvasAnimation; + sequence_type == FrameSequenceTrackerType::kCanvasAnimation || + sequence_type == FrameSequenceTrackerType::kSETMainThreadAnimation || + sequence_type == FrameSequenceTrackerType::kSETCompositorAnimation; } int FrameSequenceMetrics::ThroughputData::ReportDroppedFramePercentHistogram( @@ -692,10 +749,18 @@ void FrameSequenceMetrics::AddSortedFrame(const viz::BeginFrameArgs& args, case SmoothEffectDrivingThread::kCompositor: if (frame_info.WasSmoothCompositorUpdateDropped()) { ++v2_.frames_dropped; + ++v3_.frames_dropped; } ++v2_.frames_expected; + ++v3_.frames_expected; break; case SmoothEffectDrivingThread::kMain: + if (frame_info.WasSmoothMainUpdateExpected()) { + if (frame_info.WasSmoothMainUpdateDropped()) { + ++v3_.frames_dropped; + } + ++v3_.frames_expected; + } if (frame_info.WasSmoothMainUpdateDropped()) { ++v2_.frames_dropped; } diff --git a/chromium/cc/metrics/frame_sequence_metrics.h b/chromium/cc/metrics/frame_sequence_metrics.h index 671fc9ff578..33fa2b8ae30 100644 --- a/chromium/cc/metrics/frame_sequence_metrics.h +++ b/chromium/cc/metrics/frame_sequence_metrics.h @@ -6,9 +6,11 @@ #define CC_METRICS_FRAME_SEQUENCE_METRICS_H_ #include <bitset> +#include <cmath> #include <memory> #include "base/callback.h" +#include "base/check.h" #include "base/memory/raw_ptr.h" #include "base/trace_event/traced_value.h" #include "cc/cc_export.h" @@ -38,6 +40,8 @@ enum class FrameSequenceTrackerType { // and instead are dispatched back to the LayerTreeHostClient. kCanvasAnimation = 10, kJSAnimation = 11, + kSETMainThreadAnimation = 12, + kSETCompositorAnimation = 13, kMaxType }; @@ -233,6 +237,12 @@ class CC_EXPORT FrameSequenceMetrics { uint32_t frames_dropped = 0; } v2_; + // Track state for measuring the PercentDroppedFrames v3 metrics. + struct { + uint32_t frames_expected = 0; + uint32_t frames_dropped = 0; + } v3_; + ThroughputData impl_throughput_; ThroughputData main_throughput_; diff --git a/chromium/cc/metrics/frame_sequence_metrics_unittest.cc b/chromium/cc/metrics/frame_sequence_metrics_unittest.cc index cbef003b39b..c5729bd4883 100644 --- a/chromium/cc/metrics/frame_sequence_metrics_unittest.cc +++ b/chromium/cc/metrics/frame_sequence_metrics_unittest.cc @@ -233,4 +233,50 @@ TEST(FrameSequenceMetricsTest, ScrollingThreadMetricsReportedForInteractions) { } } +TEST(FrameSequenceMetricsTest, CompositorSharedElementTransitionReported) { + base::HistogramTester histograms; + + auto metrics = std::make_unique<FrameSequenceMetrics>( + FrameSequenceTrackerType::kSETCompositorAnimation, nullptr); + metrics->impl_throughput().frames_expected = 100; + metrics->impl_throughput().frames_produced = 80; + metrics->impl_throughput().frames_ontime = 70; + metrics->main_throughput().frames_expected = 100; + metrics->main_throughput().frames_produced = 60; + metrics->main_throughput().frames_ontime = 50; + EXPECT_TRUE(metrics->HasEnoughDataForReporting()); + metrics->ReportMetrics(); + histograms.ExpectTotalCount( + "Graphics.Smoothness.PercentDroppedFrames.CompositorThread." + "SETCompositorAnimation", + 1u); + histograms.ExpectTotalCount( + "Graphics.Smoothness.PercentDroppedFrames.MainThread." + "SETCompositorAnimation", + 0u); +} + +TEST(FrameSequenceMetricsTest, MainThreadSharedElementTransitionReported) { + base::HistogramTester histograms; + + auto metrics = std::make_unique<FrameSequenceMetrics>( + FrameSequenceTrackerType::kSETMainThreadAnimation, nullptr); + metrics->impl_throughput().frames_expected = 100; + metrics->impl_throughput().frames_produced = 80; + metrics->impl_throughput().frames_ontime = 70; + metrics->main_throughput().frames_expected = 100; + metrics->main_throughput().frames_produced = 60; + metrics->main_throughput().frames_ontime = 50; + EXPECT_TRUE(metrics->HasEnoughDataForReporting()); + metrics->ReportMetrics(); + histograms.ExpectTotalCount( + "Graphics.Smoothness.PercentDroppedFrames.CompositorThread." + "SETMainThreadAnimation", + 0u); + histograms.ExpectTotalCount( + "Graphics.Smoothness.PercentDroppedFrames.MainThread." + "SETMainThreadAnimation", + 1u); +} + } // namespace cc diff --git a/chromium/cc/metrics/frame_sequence_tracker.cc b/chromium/cc/metrics/frame_sequence_tracker.cc index baf282b87d7..8db69731d27 100644 --- a/chromium/cc/metrics/frame_sequence_tracker.cc +++ b/chromium/cc/metrics/frame_sequence_tracker.cc @@ -74,6 +74,10 @@ const char* FrameSequenceTracker::GetFrameSequenceTrackerTypeName( return "CanvasAnimation"; case FrameSequenceTrackerType::kJSAnimation: return "JSAnimation"; + case FrameSequenceTrackerType::kSETMainThreadAnimation: + return "SETMainThreadAnimation"; + case FrameSequenceTrackerType::kSETCompositorAnimation: + return "SETCompositorAnimation"; case FrameSequenceTrackerType::kMaxType: return ""; } diff --git a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc index cb3c6d72cfd..e1f7b45cad7 100644 --- a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc @@ -13,9 +13,6 @@ #include "base/test/metrics/histogram_tester.h" #include "cc/metrics/compositor_frame_reporting_controller.h" #include "cc/metrics/frame_sequence_tracker_collection.h" -#include "cc/metrics/throughput_ukm_reporter.h" -#include "cc/trees/ukm_manager.h" -#include "components/ukm/test_ukm_recorder.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -45,7 +42,8 @@ class FrameSequenceTrackerTest : public testing::Test { FrameSequenceTrackerTest() : compositor_frame_reporting_controller_( std::make_unique<CompositorFrameReportingController>( - /*should_report_metrics=*/true, + /*should_report_histograms=*/true, + /*should_report_ukm=*/false, /*layer_tree_host_id=*/1)), collection_(/*is_single_threaded=*/false, compositor_frame_reporting_controller_.get()) { diff --git a/chromium/cc/metrics/total_frame_counter.cc b/chromium/cc/metrics/total_frame_counter.cc index 1d07e354b20..7acec184658 100644 --- a/chromium/cc/metrics/total_frame_counter.cc +++ b/chromium/cc/metrics/total_frame_counter.cc @@ -4,6 +4,8 @@ #include "cc/metrics/total_frame_counter.h" +#include <cmath> + #include "base/logging.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc index 060ab11ba52..7df43281b36 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc @@ -179,7 +179,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListEmpty) { auto pass = viz::CompositorRenderPass::Create(); pass->id = viz::CompositorRenderPassId{1}; pass->output_rect = display_rect_; - pass_list.push_back(move(pass)); + pass_list.push_back(std::move(pass)); SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); @@ -194,7 +194,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { auto pass1 = viz::CompositorRenderPass::Create(); pass1->id = viz::CompositorRenderPassId{1}; pass1->output_rect = display_rect_; - pass_list.push_back(move(pass1)); + pass_list.push_back(std::move(pass1)); viz::HitTestRegionList region_list1; region_list1.flags = viz::HitTestRegionFlags::kHitTestMine; @@ -209,7 +209,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { auto pass2 = viz::CompositorRenderPass::Create(); pass2->id = viz::CompositorRenderPassId{2}; pass2->output_rect = display_rect_; - pass_list.push_back(move(pass2)); + pass_list.push_back(std::move(pass2)); SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); @@ -221,7 +221,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { auto pass3 = viz::CompositorRenderPass::Create(); pass3->id = viz::CompositorRenderPassId{3}; pass3->output_rect = display_rect_; - pass_list.push_back(move(pass3)); + pass_list.push_back(std::move(pass3)); viz::HitTestRegionList region_list2; region_list2.flags = viz::HitTestRegionFlags::kHitTestMine; @@ -242,7 +242,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, auto pass1 = viz::CompositorRenderPass::Create(); pass1->id = viz::CompositorRenderPassId{1}; pass1->output_rect = display_rect_; - pass_list.push_back(move(pass1)); + pass_list.push_back(std::move(pass1)); viz::HitTestRegionList region_list1; region_list1.flags = viz::HitTestRegionFlags::kHitTestMine; @@ -276,7 +276,7 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, auto pass3 = viz::CompositorRenderPass::Create(); pass3->id = viz::CompositorRenderPassId{3}; pass3->output_rect = display_rect_; - pass_list.push_back(move(pass3)); + pass_list.push_back(std::move(pass3)); viz::HitTestRegionList region_list3; region_list3.flags = viz::HitTestRegionFlags::kHitTestChildSurface; diff --git a/chromium/cc/mojom/render_frame_metadata.mojom b/chromium/cc/mojom/render_frame_metadata.mojom index aa861674703..3ee3462988e 100644 --- a/chromium/cc/mojom/render_frame_metadata.mojom +++ b/chromium/cc/mojom/render_frame_metadata.mojom @@ -4,6 +4,7 @@ module cc.mojom; +import "mojo/public/mojom/base/time.mojom"; import "services/viz/public/mojom/compositing/local_surface_id.mojom"; import "services/viz/public/mojom/compositing/selection.mojom"; import "services/viz/public/mojom/compositing/vertical_scroll_direction.mojom"; @@ -79,6 +80,14 @@ struct RenderFrameMetadata { viz.mojom.VerticalScrollDirection new_vertical_scroll_direction; + // The cumulative time spent performing visual updates since the last commit. + // Tracked for all `local_surface_id` before this one. + mojo_base.mojom.TimeDelta previous_surfaces_visual_update_duration; + + // The cumulative time spend performing visual updates for the current + // `local_surface_id` since the last commit. + mojo_base.mojom.TimeDelta current_surface_visual_update_duration; + // Used to position Android bottom bar, whose position is computed by the // renderer compositor. [EnableIf=is_android] diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc index 46df44bc5de..3e4cdf17c6b 100644 --- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc +++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc @@ -5,6 +5,7 @@ #include "cc/mojom/render_frame_metadata_mojom_traits.h" #include "build/build_config.h" +#include "mojo/public/cpp/base/time_mojom_traits.h" #include "services/viz/public/cpp/compositing/selection_mojom_traits.h" #include "services/viz/public/cpp/compositing/vertical_scroll_direction_mojom_traits.h" #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h" @@ -55,7 +56,11 @@ bool StructTraits< data.ReadViewportSizeInPixels(&out->viewport_size_in_pixels) && data.ReadLocalSurfaceId(&out->local_surface_id) && data.ReadNewVerticalScrollDirection( - &out->new_vertical_scroll_direction); + &out->new_vertical_scroll_direction) && + data.ReadPreviousSurfacesVisualUpdateDuration( + &out->previous_surfaces_visual_update_duration) && + data.ReadCurrentSurfaceVisualUpdateDuration( + &out->current_surface_visual_update_duration); } } // namespace mojo diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h index 18fef4ff5e6..8631acd1a6e 100644 --- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h +++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h @@ -96,6 +96,16 @@ struct COMPONENT_EXPORT(CC_SHARED_MOJOM_TRAITS) return metadata.new_vertical_scroll_direction; } + static base::TimeDelta previous_surfaces_visual_update_duration( + const cc::RenderFrameMetadata& metadata) { + return metadata.previous_surfaces_visual_update_duration; + } + + static base::TimeDelta current_surface_visual_update_duration( + const cc::RenderFrameMetadata& metadata) { + return metadata.current_surface_visual_update_duration; + } + #if BUILDFLAG(IS_ANDROID) static float bottom_controls_height(const cc::RenderFrameMetadata& metadata) { return metadata.bottom_controls_height; diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc index f26af0ff065..12767243365 100644 --- a/chromium/cc/paint/discardable_image_map_unittest.cc +++ b/chromium/cc/paint/discardable_image_map_unittest.cc @@ -917,7 +917,7 @@ TEST_F(DiscardableImageMapTest, CapturesImagesInSaveLayers) { scoped_refptr<DisplayItemList> display_list = new DisplayItemList(); display_list->StartPaint(); display_list->push<SaveLayerOp>(nullptr, &flags); - display_list->push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc); + display_list->push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc); display_list->EndPaintOfUnpaired(visible_rect); display_list->Finalize(); diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc index 68648556c39..9ba516eb5fa 100644 --- a/chromium/cc/paint/display_item_list.cc +++ b/chromium/cc/paint/display_item_list.cc @@ -322,7 +322,7 @@ sk_sp<PaintRecord> DisplayItemList::ReleaseAsRecord() { } bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect, - SkColor* color, + SkColor4f* color, int max_ops_to_analyze) { DCHECK(usage_hint_ == kTopLevelDisplayItemList); std::vector<size_t>* offsets_to_use = nullptr; @@ -336,7 +336,7 @@ bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect, SolidColorAnalyzer::DetermineIfSolidColor( &paint_op_buffer_, rect, max_ops_to_analyze, offsets_to_use); if (solid_color) { - *color = solid_color->toSkColor(); + *color = *solid_color; return true; } return false; diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h index 2bd510b99ea..0a52e86b7fe 100644 --- a/chromium/cc/paint/display_item_list.h +++ b/chromium/cc/paint/display_item_list.h @@ -183,7 +183,7 @@ class CC_PAINT_EXPORT DisplayItemList // indicates the maximum number of draw ops we consider when determining if a // rectangle is solid color. bool GetColorIfSolidInRect(const gfx::Rect& rect, - SkColor* color, + SkColor4f* color, int max_ops_to_analyze = 1); std::string ToString() const; diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc index 3246ef6de76..90608ac939f 100644 --- a/chromium/cc/paint/display_item_list_unittest.cc +++ b/chromium/cc/paint/display_item_list_unittest.cc @@ -31,6 +31,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/skia_conversions.h" +#include "ui/gfx/geometry/transform.h" namespace cc { diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc index 0a83b7597e7..7fdce720233 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.cc +++ b/chromium/cc/paint/image_transfer_cache_entry.cc @@ -296,7 +296,8 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( // 4-byte boundary. safe_size += 4; safe_size += pixmap_->computeByteSize(); - size_ = safe_size.ValueOrDefault(0); + size_ = base::bits::AlignUp(safe_size.ValueOrDefault(0), + PaintOpWriter::Alignment()); } ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( @@ -345,7 +346,8 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( safe_size += decoded_color_space_size + align; // SkColorSpace for YUVA image for (size_t i = 0; i < num_yuva_pixmaps; ++i) safe_size += SafeSizeForPixmap(*yuv_pixmaps_->at(i)); - size_ = safe_size.ValueOrDefault(0); + size_ = base::bits::AlignUp(safe_size.ValueOrDefault(0), + PaintOpWriter::Alignment()); } ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default; diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc index ef935c0bd73..57c8bf8ff07 100644 --- a/chromium/cc/paint/oop_pixeltest.cc +++ b/chromium/cc/paint/oop_pixeltest.cc @@ -80,7 +80,7 @@ scoped_refptr<DisplayItemList> MakeNoopDisplayItemList() { } // Creates a bitmap of |size| filled with pixels of |color|. -SkBitmap MakeSolidColorBitmap(gfx::Size size, SkColor color) { +SkBitmap MakeSolidColorBitmap(gfx::Size size, SkColor4f color) { SkBitmap bitmap; bitmap.allocPixels(SkImageInfo::MakeN32Premul(size.width(), size.height())); bitmap.eraseColor(color); @@ -96,9 +96,9 @@ sk_sp<SkImage> MakeSkImage(const gfx::Size& size, SkBitmap::kZeroPixels_AllocFlag); SkCanvas canvas(bitmap, SkSurfaceProps{}); - canvas.drawColor(SK_ColorMAGENTA); + canvas.drawColor(SkColors::kMagenta); SkPaint green; - green.setColor(SK_ColorGREEN); + green.setColor(SkColors::kGreen); canvas.drawRect(SkRect::MakeXYWH(10, 20, 30, 40), green); return SkImage::MakeFromBitmap(bitmap); @@ -141,7 +141,7 @@ class OopPixelTest : public testing::Test, oop_image_cache_ = std::make_unique<GpuImageDecodeCache>( raster_context_provider_.get(), true, kRGBA_8888_SkColorType, kWorkingSetSize, raster_max_texture_size, - PaintImage::kDefaultGeneratorClientId, nullptr); + PaintImage::GetNextGeneratorClientId(), nullptr); } class RasterOptions { @@ -154,7 +154,7 @@ class OopPixelTest : public testing::Test, playback_rect = gfx::Rect(playback_size); } - SkColor background_color = SK_ColorBLACK; + SkColor4f background_color = SkColors::kBlack; int msaa_sample_count = 0; bool use_lcd_text = false; PlaybackImageProvider::RasterMode image_provider_raster_mode = @@ -168,7 +168,7 @@ class OopPixelTest : public testing::Test, TargetColorParams target_color_params; bool requires_clear = false; bool preclear = false; - SkColor preclear_color; + SkColor4f preclear_color; raw_ptr<ImageDecodeCache> image_cache = nullptr; std::vector<scoped_refptr<DisplayItemList>> additional_lists; raw_ptr<PaintShader> shader_with_animated_images = nullptr; @@ -216,8 +216,9 @@ class OopPixelTest : public testing::Test, if (options.preclear) { raster_implementation->BeginRasterCHROMIUM( - options.preclear_color, /*needs_clear=*/options.preclear, - options.msaa_sample_count, msaa_mode, options.use_lcd_text, + options.preclear_color, + /*needs_clear=*/options.preclear, options.msaa_sample_count, + msaa_mode, options.use_lcd_text, /*visible=*/true, options.target_color_params.color_space, mailbox.name); raster_implementation->EndRasterCHROMIUM(); @@ -228,8 +229,9 @@ class OopPixelTest : public testing::Test, // the BeginRasterCHROMIUM call above, and we want to test that it is indeed // cleared, so set |needs_clear| to false here. raster_implementation->BeginRasterCHROMIUM( - options.background_color, /*needs_clear=*/!options.preclear, - options.msaa_sample_count, msaa_mode, options.use_lcd_text, + options.background_color, + /*needs_clear=*/!options.preclear, options.msaa_sample_count, msaa_mode, + options.use_lcd_text, /*visible=*/true, options.target_color_params.color_space, mailbox.name); size_t max_op_size_limit = @@ -384,11 +386,11 @@ TEST_F(OopPixelTest, DrawColor) { gfx::Rect rect(10, 10); auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc); display_item_list->EndPaintOfUnpaired(rect); display_item_list->Finalize(); - SkBitmap expected = MakeSolidColorBitmap(rect.size(), SK_ColorBLUE); + SkBitmap expected = MakeSolidColorBitmap(rect.size(), SkColors::kBlue); auto actual = Raster(display_item_list, rect.size()); ExpectEquals(actual, expected); @@ -398,7 +400,7 @@ TEST_F(OopPixelTest, DrawColorWithTargetColorSpace) { gfx::Rect rect(10, 10); auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc); display_item_list->EndPaintOfUnpaired(rect); display_item_list->Finalize(); @@ -407,8 +409,8 @@ TEST_F(OopPixelTest, DrawColorWithTargetColorSpace) { RasterOptions options(rect.size()); options.target_color_params.color_space = target_color_space; - SkBitmap expected = - MakeSolidColorBitmap(rect.size(), SkColorSetARGB(255, 38, 15, 221)); + SkBitmap expected = MakeSolidColorBitmap( + rect.size(), SkColor4f::FromColor(SkColorSetARGB(255, 38, 15, 221))); auto actual = Raster(display_item_list, options); ExpectEquals(actual, expected); @@ -466,7 +468,7 @@ TEST_F(OopPixelTest, DrawRecordPaintFilterTranslatedBounds) { // green, but its record bounds are configured to clip it to the bottom right // quarter of the output. PaintFlags internal_flags; - internal_flags.setColor(SK_ColorGREEN); + internal_flags.setColor(SkColors::kGreen); sk_sp<PaintOpBuffer> filter_buffer(new PaintOpBuffer); filter_buffer->push<DrawRectOp>( SkRect::MakeLTRB(output_size.width() / 2.f, 0.f, output_size.width(), @@ -482,7 +484,7 @@ TEST_F(OopPixelTest, DrawRecordPaintFilterTranslatedBounds) { auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc); display_item_list->push<SaveLayerOp>(nullptr, &record_flags); display_item_list->push<RestoreOp>(); display_item_list->EndPaintOfUnpaired(gfx::Rect(output_size)); @@ -492,9 +494,9 @@ TEST_F(OopPixelTest, DrawRecordPaintFilterTranslatedBounds) { SkImageInfo::MakeN32Premul(output_size.width(), output_size.height()); SkBitmap expected; expected.allocPixels(ii, ii.minRowBytes()); - expected.eraseColor(SK_ColorWHITE); + expected.eraseColor(SkColors::kWhite); expected.erase( - SK_ColorGREEN, + SkColors::kGreen.toSkColor(), SkIRect::MakeLTRB(output_size.width() / 2, output_size.height() / 2, output_size.width(), output_size.height())); @@ -615,7 +617,7 @@ TEST_F(OopPixelTest, DrawRecordShaderTranslatedTileRect) { // tiling starts from the origin, so starting at 2,1 in the offset_rect // below cuts off part of that, leaving two green i's. PaintFlags internal_flags; - internal_flags.setColor(SK_ColorGREEN); + internal_flags.setColor(SkColors::kGreen); sk_sp<PaintOpBuffer> shader_buffer(new PaintOpBuffer); shader_buffer->push<DrawRectOp>(SkRect::MakeXYWH(x_offset, y_offset, 1, 2), internal_flags); @@ -633,7 +635,7 @@ TEST_F(OopPixelTest, DrawRecordShaderTranslatedTileRect) { auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc); display_item_list->push<ScaleOp>(2.f, 2.f); PaintFlags raster_flags; raster_flags.setShader(paint_record_shader); @@ -681,7 +683,7 @@ TEST_F(OopPixelTest, DrawImageWithTargetColorSpace) { comparator); // Verify some conversion occurred here and that actual != bitmap. - EXPECT_NE(actual.getColor(0, 0), SK_ColorMAGENTA); + EXPECT_NE(actual.getColor(0, 0), SkColors::kMagenta.toSkColor()); } TEST_F(OopPixelTest, DrawImageWithSourceColorSpace) { @@ -823,9 +825,9 @@ TEST_F(OopPixelTest, DrawMailboxBackedImage) { expected_bitmap.allocPixels(backing_info); SkCanvas canvas(expected_bitmap, SkSurfaceProps{}); - canvas.drawColor(SK_ColorMAGENTA); + canvas.drawColor(SkColors::kMagenta); SkPaint green; - green.setColor(SK_ColorGREEN); + green.setColor(SkColors::kGreen); canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green); auto* ri = raster_context_provider_->RasterInterface(); @@ -866,13 +868,13 @@ TEST_F(OopPixelTest, Preclear) { options.resource_size = rect.size(); options.full_raster_rect = rect; options.playback_rect = rect; - options.background_color = SK_ColorMAGENTA; + options.background_color = SkColors::kMagenta; options.preclear = true; - options.preclear_color = SK_ColorGREEN; + options.preclear_color = SkColors::kGreen; auto actual = Raster(display_item_list, options); - auto expected = MakeSolidColorBitmap(rect.size(), SK_ColorGREEN); + auto expected = MakeSolidColorBitmap(rect.size(), SkColors::kGreen); ExpectEquals(actual, expected); } @@ -894,12 +896,12 @@ TEST_P(OopClearPixelTest, ClearingOpaqueCorner) { } else { options.playback_rect = options.full_raster_rect; } - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; float arbitrary_scale = 0.25f; options.post_scale = arbitrary_scale; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -942,12 +944,12 @@ TEST_F(OopPixelTest, ClearingOpaqueCornerExactEdge) { options.content_size = gfx::Size(options.full_raster_rect.right(), options.full_raster_rect.bottom()); options.playback_rect = options.full_raster_rect; - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; float arbitrary_scale = 0.25f; options.post_scale = arbitrary_scale; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -983,10 +985,10 @@ TEST_F(OopPixelTest, ClearingOpaqueCornerPartialRaster) { options.full_raster_rect.bottom()); options.playback_rect = gfx::Rect(arbitrary_offset.x() + 5, arbitrary_offset.y() + 3, 2, 3); - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Verify this is internal. EXPECT_NE(options.playback_rect.right(), options.full_raster_rect.right()); @@ -1031,11 +1033,11 @@ TEST_P(OopClearPixelTest, ClearingOpaqueLeftEdge) { options.playback_rect = options.full_raster_rect; } - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; options.post_translate = gfx::Vector2dF(0.3f, 0.7f); options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1085,12 +1087,12 @@ TEST_P(OopClearPixelTest, ClearingOpaqueRightEdge) { options.playback_rect = options.full_raster_rect; } - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; float arbitrary_scale = 0.25f; options.post_scale = arbitrary_scale; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1140,11 +1142,11 @@ TEST_P(OopClearPixelTest, ClearingOpaqueTopEdge) { } else { options.playback_rect = options.full_raster_rect; } - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; options.post_translate = gfx::Vector2dF(0.3f, 0.7f); options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1195,12 +1197,12 @@ TEST_P(OopClearPixelTest, ClearingOpaqueBottomEdge) { } else { options.playback_rect = options.full_raster_rect; } - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; float arbitrary_scale = 0.25f; options.post_scale = arbitrary_scale; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1240,13 +1242,13 @@ TEST_F(OopPixelTest, ClearingOpaqueInternal) { // Very large content rect to make this an internal tile. options.content_size = gfx::Size(1000, 1000); options.playback_rect = options.full_raster_rect; - options.background_color = SK_ColorGREEN; + options.background_color = SkColors::kGreen; options.post_translate = gfx::Vector2dF(0.3f, 0.7f); float arbitrary_scale = 1.2345f; options.post_scale = arbitrary_scale; options.requires_clear = false; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1275,12 +1277,12 @@ TEST_F(OopPixelTest, ClearingTransparentCorner) { options.content_size = gfx::Size(options.full_raster_rect.right(), options.full_raster_rect.bottom()); options.playback_rect = options.full_raster_rect; - options.background_color = SK_ColorTRANSPARENT; + options.background_color = SkColors::kTransparent; float arbitrary_scale = 3.7f; options.post_scale = arbitrary_scale; options.requires_clear = true; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1296,7 +1298,7 @@ TEST_F(OopPixelTest, ClearingTransparentCorner) { SkBitmap::kZeroPixels_AllocFlag); SkCanvas canvas(bitmap, SkSurfaceProps{}); - canvas.drawColor(SK_ColorTRANSPARENT); + canvas.drawColor(SkColors::kTransparent); ExpectEquals(oop_result, bitmap); } @@ -1310,12 +1312,12 @@ TEST_F(OopPixelTest, ClearingTransparentInternalTile) { options.full_raster_rect = gfx::Rect(arbitrary_offset, options.resource_size); options.content_size = gfx::Size(1000, 1000); options.playback_rect = options.full_raster_rect; - options.background_color = SK_ColorTRANSPARENT; + options.background_color = SkColors::kTransparent; float arbitrary_scale = 3.7f; options.post_scale = arbitrary_scale; options.requires_clear = true; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Note that clearing of the tile should supersede any early outs due to an // empty display list. This is due to the fact that partial raster may in fact @@ -1334,7 +1336,7 @@ TEST_F(OopPixelTest, ClearingTransparentInternalTile) { SkBitmap::kZeroPixels_AllocFlag); SkCanvas canvas(bitmap, SkSurfaceProps{}); - canvas.drawColor(SK_ColorTRANSPARENT); + canvas.drawColor(SkColors::kTransparent); ExpectEquals(oop_result, bitmap); } @@ -1348,12 +1350,12 @@ TEST_F(OopPixelTest, ClearingTransparentCornerPartialRaster) { options.full_raster_rect.bottom()); options.playback_rect = gfx::Rect(arbitrary_offset.x() + 5, arbitrary_offset.y() + 3, 2, 4); - options.background_color = SK_ColorTRANSPARENT; + options.background_color = SkColors::kTransparent; float arbitrary_scale = 0.23f; options.post_scale = arbitrary_scale; options.requires_clear = true; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; // Make a non-empty but noop display list to avoid early outs. auto display_item_list = MakeNoopDisplayItemList(); @@ -1372,7 +1374,7 @@ TEST_F(OopPixelTest, ClearingTransparentCornerPartialRaster) { canvas.drawColor(options.preclear_color); canvas.translate(-arbitrary_offset.x(), -arbitrary_offset.y()); canvas.clipRect(gfx::RectToSkRect(options.playback_rect)); - canvas.drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc); + canvas.drawColor(SkColors::kTransparent, SkBlendMode::kSrc); ExpectEquals(oop_result, bitmap); } @@ -1395,7 +1397,7 @@ TEST_F(OopPixelTest, DrawRectPlaybackRect) { options.content_size = gfx::Size(options.full_raster_rect.right(), options.full_raster_rect.bottom()); options.playback_rect = gfx::Rect(4, 2, 5, 6); - options.background_color = SK_ColorMAGENTA; + options.background_color = SkColors::kMagenta; auto actual = Raster(display_item_list, options); ExpectEquals(actual, FILE_PATH_LITERAL("oop_draw_rect_playback_rect.png")); @@ -1423,7 +1425,7 @@ TEST_F(OopPixelTest, DrawRectScaleTransformOptions) { options.content_size = {25, 25}; options.full_raster_rect = {5, 5, 20, 20}; options.playback_rect = {5, 5, 13, 9}; - options.background_color = SK_ColorCYAN; + options.background_color = SkColors::kCyan; options.post_translate = {0.5f, 0.25f}; options.post_scale = 2.f; @@ -1455,13 +1457,14 @@ TEST_F(OopPixelTest, DrawRectTransformOptionsFullRaster) { options.full_raster_rect = {5, 5, 20, 20}; options.playback_rect = {5, 5, 20, 20}; options.preclear = true; - options.preclear_color = SK_ColorRED; + options.preclear_color = SkColors::kRed; options.post_translate = {0.5f, 0.25f}; options.post_scale = 2.f; auto actual = Raster(display_item_list, options); - auto expected = MakeSolidColorBitmap(options.resource_size, - SkColorSetARGB(255, 64, 128, 32)); + auto expected = MakeSolidColorBitmap( + options.resource_size, + SkColor4f::FromColor(SkColorSetARGB(255, 64, 128, 32))); ExpectEquals(actual, expected); } @@ -1490,7 +1493,7 @@ TEST_F(OopPixelTest, DrawRectQueryMiddleOfDisplayList) { options.content_size = {20, 20}; options.full_raster_rect = {0, 10, 1, 10}; options.playback_rect = {0, 10, 1, 10}; - options.background_color = SK_ColorGRAY; + options.background_color = SkColors::kGray; options.post_translate = {0.f, 0.f}; options.post_scale = 2.f; @@ -1511,14 +1514,15 @@ TEST_F(OopPixelTest, DrawRectColorSpace) { display_item_list->StartPaint(); PaintFlags flags; flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); + flags.setColor(SkColors::kGreen); display_item_list->push<DrawRectOp>( gfx::RectToSkRect(gfx::Rect(options.resource_size)), flags); display_item_list->EndPaintOfUnpaired(options.full_raster_rect); display_item_list->Finalize(); - SkBitmap expected = MakeSolidColorBitmap(options.resource_size, - SkColorSetARGB(255, 117, 251, 76)); + SkBitmap expected = MakeSolidColorBitmap( + options.resource_size, + SkColor4f::FromColor(SkColorSetARGB(255, 117, 251, 76))); auto actual = Raster(display_item_list, options); ExpectEquals(actual, expected); @@ -1730,7 +1734,7 @@ class OopTextBlobPixelTest kTopLeft_GrSurfaceOrigin, &surface_props); SkCanvas* canvas = surface->getCanvas(); - canvas->clear(SK_ColorBLACK); + canvas->clear(SkColors::kBlack); DrawExpectedToCanvas(*canvas); surface->flushAndSubmit(); @@ -1769,7 +1773,7 @@ class OopTextBlobPixelTest } SkPaint text_paint; - text_paint.setColor(SK_ColorGREEN); + text_paint.setColor(SkColors::kGreen); if (filter && (strategy == TextBlobStrategy::kDirect || strategy == TextBlobStrategy::kDrawRecord)) { text_paint.setImageFilter(std::move(filter)); @@ -1868,7 +1872,7 @@ class OopTextBlobPixelTest PaintFlags text_flags; text_flags.setStyle(PaintFlags::kFill_Style); - text_flags.setColor(SK_ColorGREEN); + text_flags.setColor(SkColors::kGreen); if (filter && (strategy == TextBlobStrategy::kDirect || strategy == TextBlobStrategy::kDrawRecord)) { // If there's a filter, the only PaintFlags that are available for these @@ -2044,7 +2048,7 @@ TEST_F(OopPixelTest, DrawTextMultipleRasterCHROMIUM) { display_item_list->StartPaint(); PaintFlags flags; flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); + flags.setColor(SkColors::kGreen); display_item_list->push<DrawTextBlobOp>(BuildTextBlob(sk_typeface_1), 0.0f, kTextBlobY, flags); display_item_list->EndPaintOfUnpaired(options.full_raster_rect); @@ -2085,7 +2089,7 @@ TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) { display_item_list->StartPaint(); PaintFlags flags; flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); + flags.setColor(SkColors::kGreen); display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0.0f, kTextBlobY, flags); display_item_list->EndPaintOfUnpaired(options.full_raster_rect); @@ -2096,11 +2100,11 @@ TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) { // Perform the same operations on a software SkCanvas to produce an expected // bitmap. SkBitmap expected = - MakeSolidColorBitmap(options.resource_size, SK_ColorBLACK); + MakeSolidColorBitmap(options.resource_size, SkColors::kBlack); SkCanvas canvas(expected, SkSurfaceProps{}); - canvas.drawColor(SK_ColorBLACK); + canvas.drawColor(SkColors::kBlack); SkPaint paint; - paint.setColor(SK_ColorGREEN); + paint.setColor(SkColors::kGreen); canvas.drawTextBlob(BuildTextBlob(), 0, kTextBlobY, paint); // Allow 1% of pixels to be off by 1 due to differences between software and @@ -2254,9 +2258,9 @@ TEST_F(OopPixelTest, ReadbackImagePixels) { expected_bitmap.allocPixels(dest_info); SkCanvas canvas(expected_bitmap, SkSurfaceProps{}); - canvas.drawColor(SK_ColorMAGENTA); + canvas.drawColor(SkColors::kMagenta); SkPaint green; - green.setColor(SK_ColorGREEN); + green.setColor(SkColors::kGreen); canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green); auto* ri = raster_context_provider_->RasterInterface(); @@ -2384,14 +2388,14 @@ class OopPathPixelTest : public OopPixelTest, auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc); PaintFlags flags; flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); + flags.setColor(SkColors::kGreen); SkPath path; path.addCircle(20, 20, 10); display_item_list->push<DrawPathOp>(path, flags); - flags.setColor(SK_ColorBLUE); + flags.setColor(SkColors::kBlue); display_item_list->push<DrawRectOp>(SkRect::MakeWH(10, 10), flags); display_item_list->EndPaintOfUnpaired(options.full_raster_rect); display_item_list->Finalize(); @@ -2420,10 +2424,10 @@ TEST_F(OopPixelTest, RecordShaderExceedsMaxTextureSize) { const SkRect rect = SkRect::MakeWH(max_texture_size + 10, 10); auto shader_record = sk_make_sp<PaintRecord>(); - shader_record->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + shader_record->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc); PaintFlags flags; flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); + flags.setColor(SkColors::kGreen); shader_record->push<DrawRectOp>(rect, flags); auto shader = PaintShader::MakePaintRecord( shader_record, rect, SkTileMode::kRepeat, SkTileMode::kRepeat, nullptr); @@ -2437,7 +2441,7 @@ TEST_F(OopPixelTest, RecordShaderExceedsMaxTextureSize) { auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); - display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + display_item_list->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc); flags.setShader(shader); display_item_list->push<DrawRectOp>(rect, flags); display_item_list->EndPaintOfUnpaired(options.full_raster_rect); diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc index 50124905cd5..705aa95dabe 100644 --- a/chromium/cc/paint/paint_filter.cc +++ b/chromium/cc/paint/paint_filter.cc @@ -671,7 +671,8 @@ AlphaThresholdPaintFilter::~AlphaThresholdPaintFilter() = default; size_t AlphaThresholdPaintFilter::SerializedSize() const { size_t region_size = region_.writeToMemory(nullptr); base::CheckedNumeric<size_t> total_size; - total_size = BaseSerializedSize() + sizeof(uint64_t) + region_size + + total_size = BaseSerializedSize() + sizeof(uint64_t) + + base::bits::AlignUp(region_size, PaintOpWriter::Alignment()) + sizeof(inner_min_) + sizeof(outer_max_); total_size += GetFilterSize(input_.get()); return total_size.ValueOrDefault(0u); diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc index 29918c7a796..c80d3cc0680 100644 --- a/chromium/cc/paint/paint_flags.cc +++ b/chromium/cc/paint/paint_flags.cc @@ -144,7 +144,7 @@ SkPaint PaintFlags::ToSkPaint() const { paint.setColorFilter(color_filter_); if (image_filter_) paint.setImageFilter(image_filter_->cached_sk_filter_); - paint.setColor4f(color_); + paint.setColor(color_); paint.setStrokeWidth(width_); paint.setStrokeMiter(miter_limit_); paint.setBlendMode(getBlendMode()); diff --git a/chromium/cc/paint/paint_flags.h b/chromium/cc/paint/paint_flags.h index d3a850d2417..537c13f9b2c 100644 --- a/chromium/cc/paint/paint_flags.h +++ b/chromium/cc/paint/paint_flags.h @@ -41,12 +41,13 @@ class CC_PAINT_EXPORT PaintFlags { return static_cast<Style>(bitfields_.style_); } ALWAYS_INLINE void setStyle(Style style) { bitfields_.style_ = style; } + // TODO(crbug.com/1308932): Remove this function ALWAYS_INLINE SkColor getColor() const { return color_.toSkColor(); } ALWAYS_INLINE SkColor4f getColor4f() const { return color_; } ALWAYS_INLINE void setColor(SkColor color) { color_ = SkColor4f::FromColor(color); } - ALWAYS_INLINE void setColor4f(SkColor4f color) { color_ = color; } + ALWAYS_INLINE void setColor(SkColor4f color) { color_ = color; } ALWAYS_INLINE uint8_t getAlpha() const { return SkColorGetA(color_.toSkColor()); } @@ -205,7 +206,7 @@ class CC_PAINT_EXPORT PaintFlags { // Match(ish) SkPaint defaults. SkPaintDefaults is not public, so this // just uses these values and ignores any SkUserConfig overrides. - SkColor4f color_ = SkColor4f::FromColor(SK_ColorBLACK); + SkColor4f color_ = SkColors::kBlack; float width_ = 0.f; float miter_limit_ = 4.f; uint32_t blend_mode_ = static_cast<uint32_t>(SkBlendMode::kSrcOver); diff --git a/chromium/cc/paint/paint_image_unittest.cc b/chromium/cc/paint/paint_image_unittest.cc index 45103e503d7..66289c6c32d 100644 --- a/chromium/cc/paint/paint_image_unittest.cc +++ b/chromium/cc/paint/paint_image_unittest.cc @@ -35,7 +35,7 @@ TEST(PaintImageTest, DecodesCorrectFrames) { SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); std::vector<size_t> memory(info.computeMinByteSize()); image.Decode(memory.data(), &info, nullptr, 1u, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); ASSERT_EQ(generator->frames_decoded().size(), 1u); EXPECT_EQ(generator->frames_decoded().count(1u), 1u); generator->reset_frames_decoded(); @@ -44,7 +44,7 @@ TEST(PaintImageTest, DecodesCorrectFrames) { info.makeColorType(kRGB_565_SkColorType); memory = std::vector<size_t>(info.computeMinByteSize()); image.Decode(memory.data(), &info, nullptr, 1u, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); ASSERT_EQ(generator->frames_decoded().size(), 1u); EXPECT_EQ(generator->frames_decoded().count(1u), 1u); generator->reset_frames_decoded(); @@ -99,7 +99,7 @@ TEST(PaintImageTest, DecodeToYuv420NoAlpha) { ASSERT_EQ(yuva_pixmap_info, image_yuva_pixmap_info); image.DecodeYuv(pixmaps, 1u /* frame_index */, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); ASSERT_EQ(yuv_generator->frames_decoded().size(), 1u); EXPECT_EQ(yuv_generator->frames_decoded().count(1u), 1u); yuv_generator->reset_frames_decoded(); diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc index 683420ef063..1081d238920 100644 --- a/chromium/cc/paint/paint_op_buffer.cc +++ b/chromium/cc/paint/paint_op_buffer.cc @@ -84,6 +84,42 @@ SkRect MapRect(const SkMatrix& matrix, const SkRect& src) { matrix.mapRect(&dst, src); return dst; } + +void DrawImageRect(SkCanvas* canvas, + const SkImage* image, + const SkRect& src, + const SkRect& dst, + const SkSamplingOptions& options, + const SkPaint* paint, + SkCanvas::SrcRectConstraint constraint) { + if (!image) + return; + if (constraint == SkCanvas::kStrict_SrcRectConstraint && + options.mipmap != SkMipmapMode::kNone && + src.contains(SkRect::Make(image->dimensions()))) { + SkMatrix m; + m.setRectToRect(src, dst, SkMatrix::ScaleToFit::kFill_ScaleToFit); + canvas->save(); + canvas->concat(m); + canvas->drawImage(image, 0, 0, options, paint); + canvas->restore(); + return; + } + canvas->drawImageRect(image, src, dst, options, paint, constraint); +} + +bool GrSlugAreEqual(sk_sp<GrSlug> left, sk_sp<GrSlug> right) { + if (!left && !right) { + return true; + } + if (left && right) { + auto left_data = left->serialize(); + auto right_data = right->serialize(); + return left_data->equals(right_data.get()); + } + return false; +} + } // namespace #define TYPES(M) \ @@ -350,8 +386,7 @@ PlaybackParams::PlaybackParams(ImageProvider* image_provider, : image_provider(image_provider), original_ctm(original_ctm), custom_callback(custom_callback), - did_draw_op_callback(did_draw_op_callback), - raw_draw_analysis(false) {} + did_draw_op_callback(did_draw_op_callback) {} PlaybackParams::~PlaybackParams() {} @@ -368,8 +403,7 @@ PaintOp::SerializeOptions::SerializeOptions( SkottieSerializationHistory* skottie_serialization_history, bool can_use_lcd_text, bool context_supports_distance_field_text, - int max_texture_size, - bool raw_draw) + int max_texture_size) : image_provider(image_provider), transfer_cache(transfer_cache), paint_cache(paint_cache), @@ -379,8 +413,7 @@ PaintOp::SerializeOptions::SerializeOptions( can_use_lcd_text(can_use_lcd_text), context_supports_distance_field_text( context_supports_distance_field_text), - max_texture_size(max_texture_size), - raw_draw(raw_draw) {} + max_texture_size(max_texture_size) {} PaintOp::SerializeOptions::SerializeOptions() = default; PaintOp::SerializeOptions::SerializeOptions(const SerializeOptions&) = default; @@ -538,7 +571,7 @@ size_t DrawImageOp::Serialize(const PaintOp* base_op, helper.Write( CreateDrawImage(op->image, flags_to_serialize, op->sampling, current_ctm), &scale_adjustment); - helper.AlignMemory(alignof(SkScalar)); + helper.AssertAlignment(alignof(SkScalar)); helper.Write(scale_adjustment.width()); helper.Write(scale_adjustment.height()); @@ -569,7 +602,7 @@ size_t DrawImageRectOp::Serialize(const PaintOp* base_op, helper.Write( CreateDrawImage(op->image, flags_to_serialize, op->sampling, matrix), &scale_adjustment); - helper.AlignMemory(alignof(SkScalar)); + helper.AssertAlignment(alignof(SkScalar)); helper.Write(scale_adjustment.width()); helper.Write(scale_adjustment.height()); @@ -608,7 +641,7 @@ size_t DrawLineOp::Serialize(const PaintOp* base_op, if (!flags_to_serialize) flags_to_serialize = &op->flags; helper.Write(*flags_to_serialize, current_ctm); - helper.AlignMemory(alignof(SkScalar)); + helper.AssertAlignment(alignof(SkScalar)); helper.Write(op->x0); helper.Write(op->y0); helper.Write(op->x1); @@ -717,11 +750,14 @@ void SerializeSkottieFrameData(const SkM44& current_ctm, // |scale_adjustment| is not ultimately used; Skottie handles image // scale adjustment internally when rastering. SkSize scale_adjustment = SkSize::MakeEmpty(); - helper.Write(DrawImage(frame_data.image, /*use_dark_mode=*/false, - SkIRect::MakeWH(frame_data.image.width(), - frame_data.image.height()), - frame_data.quality, current_ctm), - &scale_adjustment); + DrawImage draw_image; + if (frame_data.image) { + draw_image = DrawImage( + frame_data.image, /*use_dark_mode=*/false, + SkIRect::MakeWH(frame_data.image.width(), frame_data.image.height()), + frame_data.quality, current_ctm); + } + helper.Write(draw_image, &scale_adjustment); helper.Write(frame_data.quality); } @@ -783,18 +819,11 @@ size_t DrawTextBlobOp::Serialize(const PaintOp* base_op, if (!flags_to_serialize) flags_to_serialize = &op->flags; helper.Write(*flags_to_serialize, current_ctm); - helper.AlignMemory(alignof(SkScalar)); - helper.Write(op->x); - helper.Write(op->y); - unsigned int count = options.raw_draw ? (op->extra_slugs.size() + 1) : 0; + unsigned int count = op->extra_slugs.size() + 1; helper.Write(count); - if (options.raw_draw) { - helper.Write(op->slug); - for (const auto& slug : op->extra_slugs) { - helper.Write(slug); - } - } else { - helper.Write(op->blob); + helper.Write(op->slug); + for (const auto& slug : op->extra_slugs) { + helper.Write(slug); } return helper.size(); } @@ -988,7 +1017,7 @@ class PaintOpDeserializer { void ReadSize(size_t* size) { reader_.ReadSize(size); } - void AlignMemory(size_t alignment) { reader_.AlignMemory(alignment); } + void AssertAlignment(size_t alignment) { reader_.AssertAlignment(alignment); } private: PaintOpReader reader_; @@ -1115,7 +1144,7 @@ PaintOp* DrawImageOp::Deserialize(const volatile void* input, deserializer.Read(&deserializer->flags); deserializer.Read(&deserializer->image); - deserializer.AlignMemory(alignof(SkScalar)); + deserializer.AssertAlignment(alignof(SkScalar)); deserializer.Read(&deserializer->scale_adjustment.fWidth); deserializer.Read(&deserializer->scale_adjustment.fHeight); @@ -1136,7 +1165,7 @@ PaintOp* DrawImageRectOp::Deserialize(const volatile void* input, deserializer.Read(&deserializer->flags); deserializer.Read(&deserializer->image); - deserializer.AlignMemory(alignof(SkScalar)); + deserializer.AssertAlignment(alignof(SkScalar)); deserializer.Read(&deserializer->scale_adjustment.fWidth); deserializer.Read(&deserializer->scale_adjustment.fHeight); @@ -1169,7 +1198,7 @@ PaintOp* DrawLineOp::Deserialize(const volatile void* input, PaintOpDeserializer<DrawLineOp> deserializer(input, input_size, options, new (output) DrawLineOp); deserializer.Read(&deserializer->flags); - deserializer.AlignMemory(alignof(SkScalar)); + deserializer.AssertAlignment(alignof(SkScalar)); deserializer.Read(&deserializer->x0); deserializer.Read(&deserializer->y0); deserializer.Read(&deserializer->x1); @@ -1284,9 +1313,6 @@ absl::optional<SkottieFrameData> DeserializeSkottieFrameData( PaintOpDeserializer<DrawSkottieOp>& deserializer) { SkottieFrameData frame_data; deserializer.Read(&frame_data.image); - if (!frame_data.image) - return absl::nullopt; - deserializer.Read(&frame_data.quality); return frame_data; } @@ -1359,19 +1385,12 @@ PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input, PaintOpDeserializer<DrawTextBlobOp> deserializer(input, input_size, options, new (output) DrawTextBlobOp); deserializer.Read(&deserializer->flags); - deserializer.AlignMemory(alignof(SkScalar)); - deserializer.Read(&deserializer->x); - deserializer.Read(&deserializer->y); unsigned int count = 0; deserializer.Read(&count); - if (count) { - deserializer.Read(&deserializer->slug); - deserializer->extra_slugs.resize(count - 1); - for (auto& slug : deserializer->extra_slugs) { - deserializer.Read(&slug); - } - } else { - deserializer.Read(&deserializer->blob); + deserializer.Read(&deserializer->slug); + deserializer->extra_slugs.resize(count - 1); + for (auto& slug : deserializer->extra_slugs) { + deserializer.Read(&slug); } return deserializer.FinalizeOp(); } @@ -1661,8 +1680,8 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op, } if (!sk_image) sk_image = op->image.GetSwSkImage(); - c->drawImageRect(sk_image.get(), adjusted_src, op->dst, op->sampling, &p, - op->constraint); + DrawImageRect(c, sk_image.get(), adjusted_src, op->dst, op->sampling, &p, + op->constraint); }); return; } @@ -1695,8 +1714,8 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op, const SkPaint& p) { SkSamplingOptions options = PaintFlags::FilterQualityToSkSamplingOptions( decoded_image.filter_quality()); - c->drawImageRect(decoded_image.image().get(), adjusted_src, op->dst, - options, &p, op->constraint); + DrawImageRect(c, decoded_image.image().get(), adjusted_src, op->dst, + options, &p, op->constraint); }); } @@ -1788,7 +1807,9 @@ SkottieWrapper::FrameDataFetchResult DrawSkottieOp::GetImageAssetForRaster( return SkottieWrapper::FrameDataFetchResult::NO_UPDATE; const SkottieFrameData& frame_data = images_iter->second; - if (params.image_provider) { + if (!frame_data.image) { + sk_image = nullptr; + } else if (params.image_provider) { // There is no use case for applying dark mode filters to skottie images // currently. DrawImage draw_image( @@ -1808,8 +1829,6 @@ SkottieWrapper::FrameDataFetchResult DrawSkottieOp::GetImageAssetForRaster( if (!sk_image) sk_image = frame_data.image.GetSwSkImage(); } - DCHECK(sk_image) << "Failed to fetch SkImage for Skottie image asset " - << asset_id; sampling_out = PaintFlags::FilterQualityToSkSamplingOptions(frame_data.quality); return SkottieWrapper::FrameDataFetchResult::NEW_DATA_AVAILABLE; @@ -1825,7 +1844,7 @@ void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op, // The PaintOpBuffer could be rasterized with different global matrix. It is // used for over scall on Android. So we cannot reuse slugs, they have to be // recreated. - if (params.raw_draw_analysis) { + if (params.is_analyzing) { const_cast<DrawTextBlobOp*>(op)->slug.reset(); const_cast<DrawTextBlobOp*>(op)->extra_slugs.clear(); } @@ -1836,7 +1855,7 @@ void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op, flags->DrawToSk(canvas, [op, ¶ms, &i](SkCanvas* c, const SkPaint& p) { if (op->blob) { c->drawTextBlob(op->blob.get(), op->x, op->y, p); - if (params.raw_draw_analysis) { + if (params.is_analyzing) { auto s = GrSlug::ConvertBlob(c, *op->blob, {op->x, op->y}, p); if (i == 0) { const_cast<DrawTextBlobOp*>(op)->slug = std::move(s); @@ -1845,7 +1864,7 @@ void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op, } } } else if (i < 1 + op->extra_slugs.size()) { - DCHECK(!params.raw_draw_analysis); + DCHECK(!params.is_analyzing); const auto& draw_slug = i == 0 ? op->slug : op->extra_slugs[i - 1]; if (draw_slug) draw_slug->draw(c); @@ -2310,10 +2329,7 @@ bool DrawTextBlobOp::AreEqual(const PaintOp* base_left, return false; if (left->node_id != right->node_id) return false; - - SkSerialProcs default_procs; - return left->blob->serialize(default_procs) - ->equals(right->blob->serialize(default_procs).get()); + return GrSlugAreEqual(left->slug, right->slug); } bool NoopOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) { @@ -2995,7 +3011,7 @@ PaintOpBuffer::PlaybackFoldingIterator::PlaybackFoldingIterator( const PaintOpBuffer* buffer, const std::vector<size_t>* offsets) : iter_(buffer, offsets), - folded_draw_color_(SK_ColorTRANSPARENT, SkBlendMode::kSrcOver) { + folded_draw_color_(SkColors::kTransparent, SkBlendMode::kSrcOver) { DCHECK(!buffer->are_ops_destroyed()); FindNextOp(); } @@ -3042,10 +3058,9 @@ void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() { static_cast<const DrawColorOp*>(draw_op)->mode == SkBlendMode::kSrcOver) { auto* draw_color_op = static_cast<const DrawColorOp*>(draw_op); - SkColor color = draw_color_op->color; - folded_draw_color_.color = SkColorSetARGB( - SkMulDiv255Round(save_op->alpha, SkColorGetA(color)), - SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); + SkColor4f color = draw_color_op->color; + folded_draw_color_.color = {color.fR, color.fG, color.fB, + save_op->alpha / 255 * color.fA}; current_op_ = &folded_draw_color_; break; } @@ -3108,6 +3123,7 @@ void PaintOpBuffer::Playback(SkCanvas* canvas, params.did_draw_op_callback); new_params.save_layer_alpha_should_preserve_lcd_text = save_layer_alpha_should_preserve_lcd_text; + new_params.is_analyzing = params.is_analyzing; for (PlaybackFoldingIterator iter(this, offsets); iter; ++iter) { const PaintOp* op = *iter; diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h index 1fb68e9240f..37f9aaad81c 100644 --- a/chromium/cc/paint/paint_op_buffer.h +++ b/chromium/cc/paint/paint_op_buffer.h @@ -35,9 +35,9 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkScalar.h" #include "ui/gfx/geometry/rect.h" @@ -145,13 +145,13 @@ struct CC_PAINT_EXPORT PlaybackParams { // `image_provider` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - ImageProvider* image_provider; + RAW_PTR_EXCLUSION ImageProvider* image_provider; SkM44 original_ctm; CustomDataRasterCallback custom_callback; DidDrawOpCallback did_draw_op_callback; absl::optional<bool> save_layer_alpha_should_preserve_lcd_text; - bool raw_draw_analysis; + bool is_analyzing = false; }; class CC_PAINT_EXPORT PaintOp { @@ -184,8 +184,7 @@ class CC_PAINT_EXPORT PaintOp { SkottieSerializationHistory* skottie_serialization_history, bool can_use_lcd_text, bool context_supports_distance_field_text, - int max_texture_size, - bool raw_draw = false); + int max_texture_size); SerializeOptions(const SerializeOptions&); SerializeOptions& operator=(const SerializeOptions&); ~SerializeOptions(); @@ -201,7 +200,6 @@ class CC_PAINT_EXPORT PaintOp { bool can_use_lcd_text = false; bool context_supports_distance_field_text = true; int max_texture_size = 0; - bool raw_draw = false; // TODO(crbug.com/1096123): Cleanup after study completion. // @@ -522,7 +520,7 @@ class CC_PAINT_EXPORT DrawColorOp final : public PaintOp { public: static constexpr PaintOpType kType = PaintOpType::DrawColor; static constexpr bool kIsDrawOp = true; - DrawColorOp(SkColor color, SkBlendMode mode) + DrawColorOp(SkColor4f color, SkBlendMode mode) : PaintOp(kType), color(color), mode(mode) {} static void Raster(const DrawColorOp* op, SkCanvas* canvas, @@ -531,7 +529,7 @@ class CC_PAINT_EXPORT DrawColorOp final : public PaintOp { static bool AreEqual(const PaintOp* left, const PaintOp* right); HAS_SERIALIZATION_FUNCTIONS(); - SkColor color; + SkColor4f color; SkBlendMode mode; private: @@ -1276,8 +1274,8 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { // `buffer_` and `ptr_` are not a raw_ptr<...> for performance reasons // (based on analysis of sampling profiler data and tab_search:top100:2020). - const PaintOpBuffer* buffer_ = nullptr; - char* ptr_ = nullptr; + RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr; + RAW_PTR_EXCLUSION char* ptr_ = nullptr; size_t op_offset_ = 0; }; @@ -1345,9 +1343,9 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { // `buffer_`, `ptr_`, and `offsets_` are not a raw_ptr<...> for performance // reasons (based on analysis of sampling profiler data and // tab_search:top100:2020). - const PaintOpBuffer* buffer_ = nullptr; - char* ptr_ = nullptr; - const std::vector<size_t>* offsets_; + RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr; + RAW_PTR_EXCLUSION char* ptr_ = nullptr; + RAW_PTR_EXCLUSION const std::vector<size_t>* offsets_; size_t op_offset_ = 0; size_t offsets_index_ = 0; @@ -1424,7 +1422,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { // `current_op_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - const PaintOp* current_op_ = nullptr; + RAW_PTR_EXCLUSION const PaintOp* current_op_ = nullptr; uint8_t current_alpha_ = 255; }; diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc index 9f5fd58efa0..3324ae0afaf 100644 --- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc +++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc @@ -11,6 +11,7 @@ #include "base/test/test_discardable_memory_allocator.h" #include "cc/paint/paint_cache.h" #include "cc/paint/paint_op_buffer.h" +#include "cc/paint/paint_op_writer.h" #include "cc/test/transfer_cache_test_helper.h" #include "components/viz/test/test_context_provider.h" #include "gpu/command_buffer/common/buffer.h" @@ -128,6 +129,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { uint32_t bytes_for_fonts = data[0]; if (bytes_for_fonts > size) bytes_for_fonts = size / 2; + // PaintOpBuffer only accepts 4 bytes aligned buffer. + bytes_for_fonts = + base::bits::AlignDown(bytes_for_fonts, cc::PaintOpWriter::Alignment()); FontSupport font_support; scoped_refptr<gpu::ServiceFontManager> font_manager( diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc index b4e479f6634..b57a7309556 100644 --- a/chromium/cc/paint/paint_op_buffer_serializer.cc +++ b/chromium/cc/paint/paint_op_buffer_serializer.cc @@ -20,11 +20,11 @@ namespace cc { namespace { -PlaybackParams MakeParams(const SkCanvas* canvas, bool raw_draw) { +PlaybackParams MakeParams(const SkCanvas* canvas) { // We don't use an ImageProvider here since the ops are played onto a no-draw // canvas for state tracking and don't need decoded images. PlaybackParams params(nullptr, canvas->getLocalToDevice()); - params.raw_draw_analysis = raw_draw; + params.is_analyzing = true; return params; } @@ -64,7 +64,7 @@ void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer, // only used for serializing the preamble and the initial save / final restore // SerializeBuffer will create its own PlaybackParams based on the // post-preamble canvas. - PlaybackParams params = MakeParams(canvas.get(), options_.raw_draw); + PlaybackParams params = MakeParams(canvas.get()); int saveCount = canvas->getSaveCount(); Save(canvas.get(), params); @@ -83,7 +83,7 @@ void PaintOpBufferSerializer::SerializeAndDestroy( // only used for serializing the preamble and the initial save / final restore // SerializeBuffer will create its own PlaybackParams based on the // post-preamble canvas. - PlaybackParams params = MakeParams(canvas.get(), options_.raw_draw); + PlaybackParams params = MakeParams(canvas.get()); int saveCount = canvas->getSaveCount(); Save(canvas.get(), params); @@ -102,7 +102,7 @@ void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer, const gfx::SizeF& post_scale) { std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_); - PlaybackParams params = MakeParams(canvas.get(), options_.raw_draw); + PlaybackParams params = MakeParams(canvas.get()); // TODO(khushalsagar): remove this clip rect if it's not needed. if (!playback_rect.IsEmpty()) { @@ -142,7 +142,8 @@ void PaintOpBufferSerializer::ClearForOpaqueRaster( SkClipOp::kDifference, false); SerializeOp(canvas, &inner_clip_op, nullptr, params); } - DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc); + DrawColorOp clear_op(SkColor4f::FromColor(preamble.background_color), + SkBlendMode::kSrc); SerializeOp(canvas, &clear_op, nullptr, params); RestoreToCount(canvas, 1, params); } @@ -165,7 +166,7 @@ void PaintOpBufferSerializer::SerializePreamble(SkCanvas* canvas, // There's not enough information at this point to know if this texture is // being reused from another tile, so the external texels could have been // cleared to some wrong value. - DrawColorOp clear(SK_ColorTRANSPARENT, SkBlendMode::kSrc); + DrawColorOp clear(SkColors::kTransparent, SkBlendMode::kSrc); SerializeOp(canvas, &clear, nullptr, params); } @@ -196,7 +197,7 @@ void PaintOpBufferSerializer::SerializePreamble(SkCanvas* canvas, // section that is being rastered. If this is opaque, trust the raster // to write all the pixels inside of the full_raster_rect. if (preamble.requires_clear && is_partial_raster) { - DrawColorOp clear_op(SK_ColorTRANSPARENT, SkBlendMode::kSrc); + DrawColorOp clear_op(SkColors::kTransparent, SkBlendMode::kSrc); SerializeOp(canvas, &clear_op, nullptr, params); } } @@ -277,7 +278,7 @@ void PaintOpBufferSerializer::SerializeBuffer( DCHECK(buffer); // This updates the original_ctm to reflect the canvas transformation at // start of this call to SerializeBuffer. - PlaybackParams params = MakeParams(canvas, options_.raw_draw); + PlaybackParams params = MakeParams(canvas); for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter; ++iter) { @@ -295,7 +296,7 @@ void PaintOpBufferSerializer::SerializeBufferAndDestroy( DCHECK(buffer); // This updates the original_ctm to reflect the canvas transformation at // start of this call to SerializeBuffer. - PlaybackParams params = MakeParams(canvas, options_.raw_draw); + PlaybackParams params = MakeParams(canvas); bool destroy_op_only = false; for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter; diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc index 460f28d8251..802675a4d1c 100644 --- a/chromium/cc/paint/paint_op_buffer_unittest.cc +++ b/chromium/cc/paint/paint_op_buffer_unittest.cc @@ -158,7 +158,7 @@ class PaintOpAppendTest : public ::testing::Test { private: SkRect rect_; PaintFlags flags_; - SkColor draw_color_ = SK_ColorRED; + SkColor4f draw_color_ = SkColors::kRed; SkBlendMode blend_ = SkBlendMode::kSrc; }; @@ -433,7 +433,8 @@ TEST(PaintOpBufferTest, SaveLayerRestore_DrawColor) { SkColor original = SkColorSetA(50, SK_ColorRED); buffer.push<SaveLayerAlphaOp>(nullptr, alpha); - buffer.push<DrawColorOp>(original, SkBlendMode::kSrcOver); + buffer.push<DrawColorOp>(SkColor4f::FromColor(original), + SkBlendMode::kSrcOver); buffer.push<RestoreOp>(); SaveCountingCanvas canvas; @@ -732,11 +733,11 @@ TEST_F(PaintOpBufferOffsetsTest, EmptyClipRectShouldRejectAnOp) { TEST_F(PaintOpBufferOffsetsTest, ContiguousIndices) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Plays all items. testing::Sequence s; @@ -751,11 +752,11 @@ TEST_F(PaintOpBufferOffsetsTest, ContiguousIndices) { TEST_F(PaintOpBufferOffsetsTest, NonContiguousIndices) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Plays 0, 1, 3, 4 indices. testing::Sequence s; @@ -769,11 +770,11 @@ TEST_F(PaintOpBufferOffsetsTest, NonContiguousIndices) { TEST_F(PaintOpBufferOffsetsTest, FirstTwoIndices) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Plays first two indices. testing::Sequence s; @@ -785,11 +786,11 @@ TEST_F(PaintOpBufferOffsetsTest, FirstTwoIndices) { TEST_F(PaintOpBufferOffsetsTest, MiddleIndex) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Plays index 2. testing::Sequence s; @@ -800,11 +801,11 @@ TEST_F(PaintOpBufferOffsetsTest, MiddleIndex) { TEST_F(PaintOpBufferOffsetsTest, LastTwoElements) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Plays last two elements. testing::Sequence s; @@ -816,14 +817,14 @@ TEST_F(PaintOpBufferOffsetsTest, LastTwoElements) { TEST_F(PaintOpBufferOffsetsTest, ContiguousIndicesWithSaveLayerAlphaRestore) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); uint8_t alpha = 100; push_op<SaveLayerAlphaOp>(nullptr, alpha); push_op<RestoreOp>(); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Items are {0, 1, save, restore, 2, 3, 4}. @@ -842,14 +843,14 @@ TEST_F(PaintOpBufferOffsetsTest, NonContiguousIndicesWithSaveLayerAlphaRestore) { testing::StrictMock<MockCanvas> canvas; - push_op<DrawColorOp>(0u, SkBlendMode::kClear); - push_op<DrawColorOp>(1u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear); uint8_t alpha = 100; push_op<SaveLayerAlphaOp>(nullptr, alpha); - push_op<DrawColorOp>(2u, SkBlendMode::kClear); - push_op<DrawColorOp>(3u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear); push_op<RestoreOp>(); - push_op<DrawColorOp>(4u, SkBlendMode::kClear); + push_op<DrawColorOp>(SkColor4f::FromColor(4u), SkBlendMode::kClear); // Items are {0, 1, save, 2, 3, restore, 4}. @@ -1205,10 +1206,9 @@ std::vector<PaintFlags> test_flags = { PaintFlags(), }; -std::vector<SkColor> test_colors = { - SkColorSetARGB(0, 0, 0, 0), SkColorSetARGB(255, 255, 255, 255), - SkColorSetARGB(0, 255, 10, 255), SkColorSetARGB(255, 0, 20, 255), - SkColorSetARGB(30, 255, 0, 255), SkColorSetARGB(255, 40, 0, 0), +std::vector<SkColor4f> test_colors = { + {0, 0, 0, 0}, {1, 1, 1, 1}, {1, 0.04, 1, 0}, + {0, 0.08, 1, 1}, {1, 0, 1, 0.12}, {0.16, 0, 0, 1}, }; std::vector<std::string> test_strings = { @@ -1547,10 +1547,23 @@ SkottieFrameDataMap GetTestImagesForSkottie(SkottieWrapper& skottie, return images; } +SkottieFrameDataMap GetNullImagesForSkottie(SkottieWrapper& skottie, float t) { + SkottieFrameDataMap images; + skottie.Seek( + t, base::BindLambdaForTesting( + [&](SkottieResourceIdHash asset_id, float t_frame, + sk_sp<SkImage>& image_out, SkSamplingOptions& sampling_out) { + images[asset_id] = SkottieFrameData(); + return SkottieWrapper::FrameDataFetchResult::NO_UPDATE; + })); + return images; +} + void PushDrawSkottieOps(PaintOpBuffer* buffer) { std::vector<scoped_refptr<SkottieWrapper>> test_skotties; std::vector<float> test_skottie_floats; std::vector<SkRect> test_skottie_rects; + std::vector<SkottieFrameDataMap> test_skottie_images; std::vector<SkottieColorMap> test_skottie_color_maps; std::vector<SkottieTextPropertyValueMap> test_skottie_text_maps; if (kIsSkottieSupported) { @@ -1559,12 +1572,22 @@ void PushDrawSkottieOps(PaintOpBuffer* buffer) { CreateSkottie(gfx::Size(100, 40), 5), CreateSkottie(gfx::Size(80, 70), 6), CreateSkottieFromString(kLottieDataWith2Assets), + CreateSkottieFromString(kLottieDataWith2Assets), CreateSkottieFromTestDataDir(kLottieDataWith2TextFileName)}; - test_skottie_floats = {0, 0.1f, 1.f, 0.2f, 0.3f}; + test_skottie_floats = {0, 0.1f, 1.f, 0.2f, 0.2f, 0.3f}; test_skottie_rects = { - SkRect::MakeXYWH(10, 20, 30, 40), SkRect::MakeXYWH(0, 5, 10, 20), - SkRect::MakeXYWH(6, 0, 3, 50), SkRect::MakeXYWH(10, 10, 100, 100), - SkRect::MakeXYWH(5, 5, 50, 50)}; + SkRect::MakeXYWH(10, 20, 30, 40), SkRect::MakeXYWH(0, 5, 10, 20), + SkRect::MakeXYWH(6, 0, 3, 50), SkRect::MakeXYWH(10, 10, 100, 100), + SkRect::MakeXYWH(10, 10, 100, 100), SkRect::MakeXYWH(5, 5, 50, 50)}; + test_skottie_images = { + SkottieFrameDataMap(), + SkottieFrameDataMap(), + SkottieFrameDataMap(), + GetTestImagesForSkottie(*test_skotties[3], test_skottie_rects[3], + PaintFlags::FilterQuality::kHigh, + test_skottie_floats[3]), + GetNullImagesForSkottie(*test_skotties[4], test_skottie_floats[4]), + SkottieFrameDataMap()}; test_skottie_color_maps = { {SkottieMapColor("green", SK_ColorGREEN), SkottieMapColor("yellow", SK_ColorYELLOW), @@ -1573,12 +1596,14 @@ void PushDrawSkottieOps(PaintOpBuffer* buffer) { {}, {SkottieMapColor("green", SK_ColorGREEN)}, {SkottieMapColor("transparent", SK_ColorTRANSPARENT)}, + {}, {}}; test_skottie_text_maps = { {}, {}, {}, {}, + {}, {{HashSkottieResourceId(kLottieDataWith2TextNode1), SkottieTextPropertyValue( std::string(kLottieDataWith2TextNode1Text.data()), @@ -1591,11 +1616,10 @@ void PushDrawSkottieOps(PaintOpBuffer* buffer) { size_t len = std::min(test_skotties.size(), test_flags.size()); for (size_t i = 0; i < len; i++) { - buffer->push<DrawSkottieOp>( - test_skotties[i], test_skottie_rects[i], test_skottie_floats[i], - GetTestImagesForSkottie(*test_skotties[i], test_skottie_rects[i], - PaintFlags::FilterQuality::kHigh, /*t=*/0), - test_skottie_color_maps[i], test_skottie_text_maps[i]); + buffer->push<DrawSkottieOp>(test_skotties[i], test_skottie_rects[i], + test_skottie_floats[i], test_skottie_images[i], + test_skottie_color_maps[i], + test_skottie_text_maps[i]); } ValidateOps<DrawSkottieOp>(buffer); } @@ -1797,7 +1821,8 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { PushDrawSkottieOps(&buffer_); break; case PaintOpType::DrawTextBlob: - PushDrawTextBlobOps(&buffer_); + // TODO(crbug.com/1321150): fix the test for DrawTextBlobs + // PushDrawTextBlobOps(&buffer_); break; case PaintOpType::Noop: PushNoopOps(&buffer_); @@ -1841,6 +1866,10 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { } bool IsTypeSupported() { + // TODO(crbug.com/1321150): fix the test for DrawTextBlobs + if (GetParamType() == PaintOpType::DrawTextBlob) + return false; + // DrawRecordOps must be flattened and are not currently serialized. All // other types must push non-zero amounts of ops in PushTestOps. return GetParamType() != PaintOpType::DrawRecord && @@ -1870,6 +1899,21 @@ TEST_P(PaintOpSerializationTest, SmokeTest) { ResizeOutputBuffer(); SimpleSerializer serializer(output_.get(), output_size_); + + auto canvas = + serializer.options_provider()->strike_server()->makeAnalysisCanvas( + 1024, 768, {}, nullptr, true); + PlaybackParams params(nullptr, canvas->getLocalToDevice()); + params.is_analyzing = true; + buffer_.Playback(canvas.get(), params); + + std::vector<uint8_t> strike_data; + serializer.options_provider()->strike_server()->writeStrikeData(&strike_data); + + if (!strike_data.empty()) { + serializer.options_provider()->strike_client()->readStrikeData( + strike_data.data(), strike_data.size()); + } serializer.Serialize(buffer_); // Expect all ops to write more than 0 bytes. @@ -1917,6 +1961,8 @@ TEST_P(PaintOpSerializationTest, SerializationFailures) { "%s #%zu", PaintOpTypeToString(GetParamType()).c_str(), op_idx)); size_t expected_bytes = bytes_written[op_idx]; EXPECT_GT(expected_bytes, 0u); + EXPECT_EQ(expected_bytes, + base::bits::AlignUp(expected_bytes, PaintOpWriter::Alignment())); // Attempt to write op into a buffer of size |i|, and only expect // it to succeed if the buffer is large enough. @@ -2036,6 +2082,10 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) { if (!PaintOp::TypeHasFlags(GetParamType())) return; + // TODO(crbug.com/1321150): fix the test for DrawTextBlobs + if (GetParamType() == PaintOpType::DrawTextBlob) + return; + PushTestOps(GetParamType()); ResizeOutputBuffer(); @@ -2179,7 +2229,7 @@ TEST(PaintOpSerializationTest, Preamble) { preamble.requires_clear = true; PaintOpBuffer buffer; - buffer.push<DrawColorOp>(SK_ColorBLUE, SkBlendMode::kSrc); + buffer.push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc); std::unique_ptr<char, base::AlignedFreeDeleter> memory( static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize, @@ -2254,7 +2304,7 @@ TEST(PaintOpSerializationTest, Preamble) { ASSERT_EQ(op->GetType(), PaintOpType::DrawColor) << PaintOpTypeToString(op->GetType()); const auto* draw_color_op = static_cast<const DrawColorOp*>(op); - EXPECT_EQ(draw_color_op->color, SK_ColorTRANSPARENT); + EXPECT_EQ(draw_color_op->color, SkColors::kTransparent); EXPECT_EQ(draw_color_op->mode, SkBlendMode::kSrc); continue; } @@ -2464,7 +2514,7 @@ TEST(PaintOpBufferTest, PaintOpDeserialize) { static_cast<char*>(base::AlignedAlloc(kSize, kAlign))); PaintOpBuffer buffer; - buffer.push<DrawColorOp>(SK_ColorMAGENTA, SkBlendMode::kSrc); + buffer.push<DrawColorOp>(SkColors::kMagenta, SkBlendMode::kSrc); PaintOpBuffer::Iterator iter(&buffer); PaintOp* op = *iter; @@ -2580,7 +2630,7 @@ TEST(PaintOpBufferTest, ValidateSkBlendMode) { PaintOpBuffer buffer; // Successful first two ops. - buffer.push<DrawColorOp>(SK_ColorMAGENTA, SkBlendMode::kDstIn); + buffer.push<DrawColorOp>(SkColors::kMagenta, SkBlendMode::kDstIn); PaintFlags good_flags = test_flags[0]; good_flags.setBlendMode(SkBlendMode::kColorBurn); buffer.push<DrawRectOp>(test_rects[0], good_flags); @@ -2613,7 +2663,7 @@ TEST(PaintOpBufferTest, ValidateSkBlendMode) { }; for (size_t i = 0; i < std::size(bad_modes_for_draw_color); ++i) { - buffer.push<DrawColorOp>(SK_ColorMAGENTA, bad_modes_for_draw_color[i]); + buffer.push<DrawColorOp>(SkColors::kMagenta, bad_modes_for_draw_color[i]); } for (size_t i = 0; i < std::size(bad_modes_for_flags); ++i) { @@ -2932,7 +2982,7 @@ TEST(PaintOpBufferTest, SkipsOpsWithFailedDecodes) { image_flags.setShader(PaintShader::MakeImage(paint_image, SkTileMode::kRepeat, SkTileMode::kRepeat, nullptr)); buffer.push<DrawRectOp>(SkRect::MakeXYWH(110, 110, 100, 100), image_flags); - buffer.push<DrawColorOp>(SK_ColorRED, SkBlendMode::kSrcOver); + buffer.push<DrawColorOp>(SkColors::kRed, SkBlendMode::kSrcOver); testing::StrictMock<MockCanvas> canvas; testing::Sequence s; @@ -3553,6 +3603,23 @@ TEST(PaintOpBufferTest, DrawSkottieOpRasterWithoutImageAssets) { } } +TEST(PaintOpBufferTest, DrawSkottieOpRasterWithNullImages) { + scoped_refptr<SkottieWrapper> skottie = + CreateSkottieFromString(kLottieDataWith2Assets); + SkRect skottie_rect = SkRect::MakeWH(100, 100); + + SkottieFrameDataMap images_in = GetNullImagesForSkottie(*skottie, /*t=*/0.1f); + ASSERT_FALSE(images_in.empty()); + DrawSkottieOp skottie_op(skottie, skottie_rect, /*t=*/0.1, images_in, + SkottieColorMap(), SkottieTextPropertyValueMap()); + PlaybackParams playback_params(/*image_provider=*/nullptr); + { + NiceMock<MockCanvas> canvas; + EXPECT_CALL(canvas, onDrawImage2(_, _, _, _, _)).Times(0); + DrawSkottieOp::Raster(&skottie_op, &canvas, playback_params); + } +} + TEST(PaintOpBufferTest, DrawSkottieOpRasterWithoutImageProvider) { scoped_refptr<SkottieWrapper> skottie = CreateSkottieFromString(kLottieDataWith2Assets); diff --git a/chromium/cc/paint/paint_op_helper_unittest.cc b/chromium/cc/paint/paint_op_helper_unittest.cc index e7f7fc93768..8a4aa431d23 100644 --- a/chromium/cc/paint/paint_op_helper_unittest.cc +++ b/chromium/cc/paint/paint_op_helper_unittest.cc @@ -56,9 +56,11 @@ TEST(PaintOpHelper, ConcatToString) { } TEST(PaintOpHelper, DrawColorToString) { - DrawColorOp op(SkColorSetARGB(11, 22, 33, 44), SkBlendMode::kSrc); + DrawColorOp op({0.1, 0.2, 0.3, 0.4}, SkBlendMode::kSrc); std::string str = PaintOpHelper::ToString(&op); - EXPECT_EQ(str, "DrawColorOp(color=rgba(22, 33, 44, 11), mode=kSrc)"); + EXPECT_EQ(str, + "DrawColorOp(color=rgba(0.100000, 0.200000, 0.300000, 0.400000), " + "mode=kSrc)"); } TEST(PaintOpHelper, DrawDRRectToString) { diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc index 39584797d3b..26278227497 100644 --- a/chromium/cc/paint/paint_op_reader.cc +++ b/chromium/cc/paint/paint_op_reader.cc @@ -8,6 +8,7 @@ #include <algorithm> #include <memory> +#include <type_traits> #include <utility> #include <vector> @@ -35,7 +36,6 @@ #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkSerialProcs.h" -#include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/private/chromium/GrSlug.h" #include "third_party/skia/include/private/chromium/SkChromeRemoteGlyphCache.h" @@ -52,24 +52,6 @@ bool IsValidPaintShaderScalingBehavior(PaintShader::ScalingBehavior behavior) { behavior == PaintShader::ScalingBehavior::kFixedScale; } -struct TypefaceCtx { - explicit TypefaceCtx(SkStrikeClient* client) : client(client) {} - bool invalid_typeface = false; - raw_ptr<SkStrikeClient> client = nullptr; -}; - -sk_sp<SkTypeface> DeserializeTypeface(const void* data, - size_t length, - void* ctx) { - auto* typeface_ctx = static_cast<TypefaceCtx*>(ctx); - auto tf = typeface_ctx->client->deserializeTypeface(data, length); - if (tf) - return tf; - - typeface_ctx->invalid_typeface = true; - return nullptr; -} - } // namespace // static @@ -104,15 +86,16 @@ bool PaintOpReader::ReadAndValidateOpHeader(const volatile void* input, template <typename T> void PaintOpReader::ReadSimple(T* val) { - static_assert(base::is_trivially_copyable<T>::value, - "Not trivially copyable"); + static_assert(std::is_trivially_copyable_v<T>); + DCHECK_EQ(memory_, base::bits::AlignUp(memory_, PaintOpWriter::Alignment())); // Align everything to 4 bytes, as the writer does. - static constexpr size_t kAlign = 4; - size_t size = base::bits::AlignUp(sizeof(T), kAlign); + static constexpr size_t size = + base::bits::AlignUp(sizeof(T), PaintOpWriter::Alignment()); if (remaining_bytes_ < size) SetInvalid(DeserializationError::kInsufficientRemainingBytes_ReadSimple); + if (!valid_) return; @@ -143,38 +126,43 @@ void PaintOpReader::ReadFlattenable( DeserializationError error_on_factory_failure) { size_t bytes = 0; ReadSize(&bytes); - if (remaining_bytes_ < bytes) + if (remaining_bytes_ < bytes) { SetInvalid( DeserializationError::kInsufficientRemainingBytes_ReadFlattenable); - if (!valid_) return; + } + if (bytes == 0) return; auto* scratch = CopyScratchSpace(bytes); val->reset(factory(scratch, bytes, nullptr).release()); - if (!val) + if (!val) { SetInvalid(error_on_factory_failure); + return; + } - memory_ += bytes; - remaining_bytes_ -= bytes; + DidRead(bytes); } void PaintOpReader::ReadData(size_t bytes, void* data) { - if (remaining_bytes_ < bytes) - SetInvalid(DeserializationError::kInsufficientRemainingBytes_ReadData); - if (!valid_) - return; + DCHECK_EQ(memory_, base::bits::AlignUp(memory_, PaintOpWriter::Alignment())); if (bytes == 0) return; + if (remaining_bytes_ < bytes) { + SetInvalid(DeserializationError::kInsufficientRemainingBytes_ReadData); + return; + } + memcpy(data, const_cast<const char*>(memory_), bytes); - memory_ += bytes; - remaining_bytes_ -= bytes; + DidRead(bytes); } void PaintOpReader::ReadSize(size_t* size) { AlignMemory(8); + if (!valid_) + return; uint64_t size64 = 0; ReadSimple(&size64); *size = size64; @@ -213,6 +201,10 @@ void PaintOpReader::Read(SkRRect* rect) { ReadSimple(rect); } +void PaintOpReader::Read(SkColor4f* color) { + ReadSimple(color); +} + void PaintOpReader::Read(SkPath* path) { uint32_t path_id; ReadSimple(&path_id); @@ -260,8 +252,7 @@ void PaintOpReader::Read(SkPath* path) { // do any caching either. path->setIsVolatile(true); } - memory_ += path_bytes; - remaining_bytes_ -= path_bytes; + DidRead(path_bytes); return; } } @@ -458,9 +449,7 @@ void PaintOpReader::Read(sk_sp<SkData>* data) { // This is safe to cast away the volatile as it is just a memcpy internally. *data = SkData::MakeWithCopy(const_cast<const char*>(memory_), bytes); - - memory_ += bytes; - remaining_bytes_ -= bytes; + DidRead(bytes); } void PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) { @@ -477,78 +466,32 @@ void PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) { if (!color_space) SetInvalid(DeserializationError::kSkColorSpaceDeserializeFailure); - memory_ += size; - remaining_bytes_ -= size; + DidRead(size); } + void PaintOpReader::Read(sk_sp<GrSlug>* slug) { - AlignMemory(4); + AssertAlignment(PaintOpWriter::Alignment()); size_t data_bytes = 0u; ReadSize(&data_bytes); - if (data_bytes == 0) { *slug = nullptr; return; } - if (remaining_bytes_ < data_bytes) - SetInvalid( - DeserializationError::kInsufficientRemainingBytes_Read_SkTextBlob); - if (!valid_) + + if (remaining_bytes_ < data_bytes) { + SetInvalid(DeserializationError::kInsufficientRemainingBytes_Read_GrSlug); return; + } *slug = GrSlug::Deserialize(const_cast<const char*>(memory_), data_bytes, options_.strike_client); - memory_ += data_bytes; - remaining_bytes_ -= data_bytes; -} + DidRead(data_bytes); -void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) { - AlignMemory(4); - uint32_t blob_id = 0u; - Read(&blob_id); - if (!valid_) - return; - - size_t data_bytes = 0u; - ReadSize(&data_bytes); - if (remaining_bytes_ < data_bytes) - SetInvalid( - DeserializationError::kInsufficientRemainingBytes_Read_SkTextBlob); - if (!valid_) - return; - - if (data_bytes == 0u) { - auto cached_blob = options_.paint_cache->GetTextBlob(blob_id); - if (!cached_blob) { - SetInvalid(DeserializationError::kMissingPaintCacheTextBlobEntry); - return; - } - - *blob = std::move(cached_blob); - return; - } - - DCHECK(options_.strike_client); - SkDeserialProcs procs; - TypefaceCtx typeface_ctx(options_.strike_client); - procs.fTypefaceProc = &DeserializeTypeface; - procs.fTypefaceCtx = &typeface_ctx; - auto* scratch = CopyScratchSpace(data_bytes); - sk_sp<SkTextBlob> deserialized_blob = - SkTextBlob::Deserialize(scratch, data_bytes, procs); - if (!deserialized_blob) { - SetInvalid(DeserializationError::kSkTextBlobDeserializeFailure); - return; - } - if (typeface_ctx.invalid_typeface) { - SetInvalid(DeserializationError::kInvalidTypeface); + if (!*slug) { + SetInvalid(DeserializationError::kGrSlugDeserializeFailure); return; } - options_.paint_cache->PutTextBlob(blob_id, deserialized_blob); - - *blob = std::move(deserialized_blob); - memory_ += data_bytes; - remaining_bytes_ -= data_bytes; } void PaintOpReader::Read(sk_sp<PaintShader>* shader) { @@ -781,8 +724,7 @@ void PaintOpReader::Read(scoped_refptr<SkottieWrapper>* skottie) { valid_ = false; return; } - memory_ += bytes_to_skip; - remaining_bytes_ -= bytes_to_skip; + DidRead(bytes_to_skip); } void PaintOpReader::AlignMemory(size_t alignment) { @@ -819,8 +761,7 @@ const volatile void* PaintOpReader::ExtractReadableMemory(size_t bytes) { return nullptr; const volatile void* extracted_memory = memory_; - memory_ += bytes; - remaining_bytes_ -= bytes; + DidRead(bytes); return extracted_memory; } @@ -844,7 +785,7 @@ void PaintOpReader::Read(sk_sp<PaintFilter>* filter) { crop_rect.emplace(rect); } - AlignMemory(4); + AssertAlignment(PaintOpWriter::Alignment()); switch (type) { case PaintFilter::Type::kNullFilter: NOTREACHED(); @@ -1466,8 +1407,7 @@ size_t PaintOpReader::Read(sk_sp<PaintRecord>* record) { SetInvalid(DeserializationError::kPaintOpBufferMakeFromMemoryFailure); return 0; } - memory_ += size_bytes; - remaining_bytes_ -= size_bytes; + DidRead(size_bytes); return size_bytes; } @@ -1489,4 +1429,13 @@ void PaintOpReader::Read(SkRegion* region) { SetInvalid(DeserializationError::kSkRegionReadFromMemoryFailure); } +inline void PaintOpReader::DidRead(size_t bytes_read) { + // All data are aligned with PaintOpWriter::Alignment() at least. + size_t aligned_bytes = + base::bits::AlignUp(bytes_read, PaintOpWriter::Alignment()); + memory_ += aligned_bytes; + DCHECK_LE(aligned_bytes, remaining_bytes_); + remaining_bytes_ -= aligned_bytes; +} + } // namespace cc diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h index c5b5e6e1e08..63aabf42e95 100644 --- a/chromium/cc/paint/paint_op_reader.h +++ b/chromium/cc/paint/paint_op_reader.h @@ -35,11 +35,17 @@ class CC_PAINT_EXPORT PaintOpReader { bool enable_security_constraints = false) : memory_(static_cast<const volatile char*>(memory) + PaintOpWriter::HeaderBytes()), - remaining_bytes_(size - PaintOpWriter::HeaderBytes()), + remaining_bytes_( + base::bits::AlignDown(size, PaintOpWriter::Alignment())), options_(options), enable_security_constraints_(enable_security_constraints) { - if (size < PaintOpWriter::HeaderBytes()) + DCHECK_EQ(memory_, + base::bits::AlignUp(memory_, PaintOpWriter::Alignment())); + if (remaining_bytes_ < PaintOpWriter::HeaderBytes()) { valid_ = false; + return; + } + remaining_bytes_ -= PaintOpWriter::HeaderBytes(); } static void FixupMatrixPostSerialization(SkMatrix* matrix); @@ -62,12 +68,12 @@ class CC_PAINT_EXPORT PaintOpReader { void Read(SkRect* rect); void Read(SkIRect* rect); void Read(SkRRect* rect); + void Read(SkColor4f* color); void Read(SkPath* path); void Read(PaintFlags* flags); void Read(PaintImage* image); void Read(sk_sp<SkData>* data); - void Read(sk_sp<SkTextBlob>* blob); void Read(sk_sp<GrSlug>* slug); void Read(sk_sp<PaintFilter>* filter); void Read(sk_sp<PaintShader>* shader); @@ -126,6 +132,13 @@ class CC_PAINT_EXPORT PaintOpReader { // Aligns the memory to the given alignment. void AlignMemory(size_t alignment); + void AssertAlignment(size_t alignment) { +#if DCHECK_IS_ON() + uintptr_t memory = reinterpret_cast<uintptr_t>(memory_); + DCHECK_EQ(base::bits::AlignUp(memory, alignment), memory); +#endif + } + private: enum class DeserializationError { // Enum values must remain synchronized with PaintOpDeserializationError @@ -142,7 +155,7 @@ class CC_PAINT_EXPORT PaintOpReader { kInsufficientRemainingBytes_Read_SkData = 9, kInsufficientRemainingBytes_Read_SkPath = 10, kInsufficientRemainingBytes_Read_SkRegion = 11, - kInsufficientRemainingBytes_Read_SkTextBlob = 12, + kInsufficientRemainingBytes_Read_GrSlug = 12, kInsufficientRemainingBytes_ReadData = 13, kInsufficientRemainingBytes_ReadFlattenable = 14, kInsufficientRemainingBytes_ReadMatrixConvolutionPaintFilter = 15, @@ -173,7 +186,7 @@ class CC_PAINT_EXPORT PaintOpReader { kSkPathEffectUnflattenFailure = 40, kSkPathReadFromMemoryFailure = 41, kSkRegionReadFromMemoryFailure = 42, - kSkTextBlobDeserializeFailure = 43, + kGrSlugDeserializeFailure = 43, kUnexpectedPaintShaderType = 44, kUnexpectedSerializedImageType = 45, kZeroMailbox = 46, @@ -293,6 +306,7 @@ class CC_PAINT_EXPORT PaintOpReader { void Read(SkRegion* region); uint8_t* CopyScratchSpace(size_t bytes); + void DidRead(size_t bytes_read); const volatile char* memory_ = nullptr; size_t remaining_bytes_ = 0u; diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc index 8e9e62af3f1..f899b75f254 100644 --- a/chromium/cc/paint/paint_op_writer.cc +++ b/chromium/cc/paint/paint_op_writer.cc @@ -5,6 +5,7 @@ #include "cc/paint/paint_op_writer.h" #include <memory> +#include <type_traits> #include "base/bits.h" #include "base/notreached.h" @@ -34,8 +35,6 @@ #include "third_party/skia/include/core/SkScalar.h" #include "third_party/skia/include/core/SkSerialProcs.h" #include "third_party/skia/include/core/SkSize.h" -#include "third_party/skia/include/core/SkTextBlob.h" -#include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/private/chromium/GrSlug.h" #include "third_party/skia/include/private/chromium/SkChromeRemoteGlyphCache.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -43,7 +42,6 @@ namespace cc { namespace { -constexpr size_t kSkiaAlignment = 4u; SkIRect MakeSrcRect(const PaintImage& image) { if (!image) @@ -98,26 +96,26 @@ PaintOpWriter::PaintOpWriter(void* memory, const PaintOp::SerializeOptions& options, bool enable_security_constraints) : memory_(static_cast<char*>(memory) + HeaderBytes()), - size_(size), - remaining_bytes_(size - HeaderBytes()), + size_(base::bits::AlignDown(size, Alignment())), + remaining_bytes_(size_ - HeaderBytes()), options_(options), enable_security_constraints_(enable_security_constraints) { // Leave space for header of type/skip. DCHECK_GE(size, HeaderBytes()); + DCHECK_EQ(memory_.get(), base::bits::AlignUp(memory_.get(), Alignment())); } PaintOpWriter::~PaintOpWriter() = default; template <typename T> void PaintOpWriter::WriteSimple(const T& val) { - static_assert(base::is_trivially_copyable<T>::value, ""); + static_assert(std::is_trivially_copyable_v<T>); // Round up each write to 4 bytes. This is not technically perfect alignment, // but it is about 30% faster to post-align each write to 4 bytes than it is // to pre-align memory to the correct alignment. - // TODO(enne): maybe we should do this correctly and DCHECK alignment. - static constexpr size_t kAlign = 4; - size_t size = base::bits::AlignUp(sizeof(T), kAlign); + DCHECK_EQ(memory_.get(), base::bits::AlignUp(memory_.get(), Alignment())); + static constexpr size_t size = base::bits::AlignUp(sizeof(T), Alignment()); EnsureBytes(size); if (!valid_) return; @@ -138,14 +136,13 @@ void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) { return; size_t bytes_written = val->serialize( - memory_, base::bits::AlignDown(remaining_bytes_, kSkiaAlignment)); + memory_, base::bits::AlignDown(remaining_bytes_, Alignment())); if (bytes_written == 0u) { valid_ = false; return; } *size_memory = bytes_written; - memory_ += bytes_written; - remaining_bytes_ -= bytes_written; + DidWrite(bytes_written); } uint64_t* PaintOpWriter::WriteSize(size_t size) { @@ -187,6 +184,10 @@ void PaintOpWriter::Write(const SkRRect& rect) { WriteSimple(rect); } +void PaintOpWriter::Write(const SkColor4f& color) { + WriteSimple(color); +} + void PaintOpWriter::Write(const SkPath& path, UsePaintCache use_paint_cache) { auto id = path.getGenerationID(); if (!options_.for_identifiability_study) @@ -226,8 +227,7 @@ void PaintOpWriter::Write(const SkPath& path, UsePaintCache use_paint_cache) { options_.paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written); } *bytes_to_skip = bytes_written; - memory_ += bytes_written; - remaining_bytes_ -= bytes_written; + DidWrite(bytes_written); } void PaintOpWriter::Write(const PaintFlags& flags, const SkM44& current_ctm) { @@ -317,8 +317,7 @@ void PaintOpWriter::Write(scoped_refptr<SkottieWrapper> skottie) { DCHECK_LE(bytes_written, remaining_bytes_); *bytes_to_skip = bytes_written; - memory_ += bytes_written; - remaining_bytes_ -= bytes_written; + DidWrite(bytes_written); } void PaintOpWriter::WriteImage(const DecodedDrawImage& decoded_draw_image) { @@ -356,8 +355,7 @@ void PaintOpWriter::WriteImage(const gpu::Mailbox& mailbox) { return; memcpy(memory_, mailbox.name, sizeof(mailbox.name)); - memory_ += sizeof(mailbox.name); - remaining_bytes_ -= sizeof(mailbox.name); + DidWrite(sizeof(mailbox.name)); } void PaintOpWriter::Write(const sk_sp<SkData>& data) { @@ -397,16 +395,14 @@ void PaintOpWriter::Write(const SkColorSpace* color_space) { size_t written = color_space->writeToMemory(memory_); CHECK_EQ(written, size); - - memory_ += written; - remaining_bytes_ -= written; + DidWrite(written); } void PaintOpWriter::Write(const sk_sp<GrSlug>& slug) { if (!valid_) return; - AlignMemory(4); + AssertAlignment(Alignment()); uint64_t* size_memory = WriteSize(0u); if (!valid_) return; @@ -416,52 +412,15 @@ void PaintOpWriter::Write(const sk_sp<GrSlug>& slug) { // TODO(penghuang): should we use a unique id to avoid sending the same // slug? bytes_written = slug->serialize( - memory_, base::bits::AlignDown(remaining_bytes_, kSkiaAlignment)); + memory_, base::bits::AlignDown(remaining_bytes_, Alignment())); if (bytes_written == 0u) { valid_ = false; return; } } - *size_memory = bytes_written; - memory_ += bytes_written; - remaining_bytes_ -= bytes_written; -} - -void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) { - DCHECK(blob); - if (!valid_) - return; - - AlignMemory(4); - uint32_t blob_id = blob->uniqueID(); - Write(blob_id); - uint64_t* size_memory = WriteSize(0u); - if (!valid_) - return; - - if (options_.paint_cache->Get(PaintCacheDataType::kTextBlob, blob_id)) - return; - - auto encodeTypeface = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> { - return static_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf); - }; - DCHECK(options_.strike_server); - SkSerialProcs procs; - procs.fTypefaceProc = encodeTypeface; - procs.fTypefaceCtx = options_.strike_server; - - size_t bytes_written = blob->serialize( - procs, memory_, base::bits::AlignDown(remaining_bytes_, kSkiaAlignment)); - if (bytes_written == 0u) { - valid_ = false; - return; - } - options_.paint_cache->Put(PaintCacheDataType::kTextBlob, blob_id, - bytes_written); *size_memory = bytes_written; - memory_ += bytes_written; - remaining_bytes_ -= bytes_written; + DidWrite(bytes_written); } sk_sp<PaintShader> PaintOpWriter::TransformShaderIfNecessary( @@ -607,15 +566,18 @@ void PaintOpWriter::Write(SkYUVAInfo::Subsampling subsampling) { } void PaintOpWriter::WriteData(size_t bytes, const void* input) { + DCHECK_EQ(memory_.get(), + base::bits::AlignUp(memory_.get(), PaintOpWriter::Alignment())); + if (bytes == 0) + return; + EnsureBytes(bytes); + if (!valid_) return; - if (bytes == 0) - return; memcpy(memory_, input, bytes); - memory_ += bytes; - remaining_bytes_ -= bytes; + DidWrite(bytes); } void PaintOpWriter::AlignMemory(size_t alignment) { @@ -652,7 +614,7 @@ void PaintOpWriter::Write(const PaintFilter* filter, const SkM44& current_ctm) { if (!valid_) return; - AlignMemory(kSkiaAlignment); + AssertAlignment(Alignment()); switch (filter->type()) { case PaintFilter::Type::kNullFilter: NOTREACHED(); @@ -1006,8 +968,7 @@ void PaintOpWriter::Write(const PaintRecord* record, // The serializer should have failed if it ran out of space. DCHECK to verify // that it wrote at most as many bytes as we had left. DCHECK_LE(serializer.written(), remaining_bytes_); - memory_ += serializer.written(); - remaining_bytes_ -= serializer.written(); + DidWrite(serializer.written()); } void PaintOpWriter::Write(const SkRegion& region) { @@ -1020,6 +981,14 @@ void PaintOpWriter::Write(const SkRegion& region) { WriteData(bytes_written, data.get()); } +inline void PaintOpWriter::DidWrite(size_t bytes_written) { + // All data are aligned with PaintOpWriter::Alignment() at least. + size_t aligned_bytes = base::bits::AlignUp(bytes_written, Alignment()); + memory_ += aligned_bytes; + DCHECK_LE(aligned_bytes, remaining_bytes_); + remaining_bytes_ -= aligned_bytes; +} + inline void PaintOpWriter::EnsureBytes(size_t required_bytes) { if (remaining_bytes_ < required_bytes) valid_ = false; diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h index 0c35f8e7d60..defb8ce9c99 100644 --- a/chromium/cc/paint/paint_op_writer.h +++ b/chromium/cc/paint/paint_op_writer.h @@ -60,11 +60,11 @@ class CC_PAINT_EXPORT PaintOpWriter { void Write(const SkRect& rect); void Write(const SkIRect& rect); void Write(const SkRRect& rect); + void Write(const SkColor4f& color); void Write(const SkPath& path, UsePaintCache); void Write(const sk_sp<SkData>& data); void Write(const SkColorSpace* data); void Write(const SkSamplingOptions&); - void Write(const sk_sp<SkTextBlob>& blob); void Write(const sk_sp<GrSlug>& slug); void Write(SkYUVColorSpace yuv_color_space); void Write(SkYUVAInfo::PlaneConfig plane_config); @@ -98,6 +98,13 @@ class CC_PAINT_EXPORT PaintOpWriter { // Aligns the memory to the given alignment. void AlignMemory(size_t alignment); + void AssertAlignment(size_t alignment) { +#if DCHECK_IS_ON() + uintptr_t memory = reinterpret_cast<uintptr_t>(memory_.get()); + DCHECK_EQ(base::bits::AlignUp(memory, alignment), memory); +#endif + } + // sk_sp is implicitly convertible to uint8_t (likely via implicit bool // conversion). In order to avoid accidentally calling that overload instead // of a specific function (such as would be the case if one forgets to call @@ -171,7 +178,7 @@ class CC_PAINT_EXPORT PaintOpWriter { void WriteImage(const DecodedDrawImage& decoded_draw_image); void WriteImage(uint32_t transfer_cache_entry_id, bool needs_mips); void WriteImage(const gpu::Mailbox& mailbox); - + void DidWrite(size_t bytes_written); void EnsureBytes(size_t required_bytes); sk_sp<PaintShader> TransformShaderIfNecessary( const PaintShader* original, diff --git a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc index c6e4f150185..e5d985af10d 100644 --- a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc +++ b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc @@ -7,6 +7,8 @@ #include <string.h> #include <utility> +#include "base/check_op.h" + namespace cc { ClientRawMemoryTransferCacheEntry::ClientRawMemoryTransferCacheEntry( diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc index 4938ba5ab52..0f917af47e1 100644 --- a/chromium/cc/paint/record_paint_canvas.cc +++ b/chromium/cc/paint/record_paint_canvas.cc @@ -228,11 +228,11 @@ bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const { } void RecordPaintCanvas::drawColor(SkColor color, SkBlendMode mode) { - push<DrawColorOp>(color, mode); + push<DrawColorOp>(SkColor4f::FromColor(color), mode); } void RecordPaintCanvas::clear(SkColor color) { - push<DrawColorOp>(color, SkBlendMode::kSrc); + push<DrawColorOp>(SkColor4f::FromColor(color), SkBlendMode::kSrc); } void RecordPaintCanvas::drawLine(SkScalar x0, diff --git a/chromium/cc/paint/skottie_frame_data.h b/chromium/cc/paint/skottie_frame_data.h index c76115f0f3a..0629918093b 100644 --- a/chromium/cc/paint/skottie_frame_data.h +++ b/chromium/cc/paint/skottie_frame_data.h @@ -28,7 +28,7 @@ struct CC_PAINT_EXPORT SkottieFrameData { PaintImage image; // Chromium version of SkSamplingOptions. Controls resampling quality if the // image needs to be resized when rendering. - PaintFlags::FilterQuality quality; + PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow; }; CC_PAINT_EXPORT bool operator==(const SkottieFrameData& frame_l, diff --git a/chromium/cc/paint/skottie_frame_data_provider.h b/chromium/cc/paint/skottie_frame_data_provider.h index d6064763f12..27559f0c4b5 100644 --- a/chromium/cc/paint/skottie_frame_data_provider.h +++ b/chromium/cc/paint/skottie_frame_data_provider.h @@ -32,6 +32,9 @@ class CC_PAINT_EXPORT SkottieFrameDataProvider { class CC_PAINT_EXPORT ImageAsset : public base::RefCounted<ImageAsset> { public: // Returns the image to use for an asset in a frame of a skottie animation. + // May return a blank SkottieFrameData instance with an empty |image|. + // Skottie handles this gracefully and simply skips the image asset while + // still rendering the rest of the frame. // // |t|: See skresources::ImageAsset::getFrame(). Same semantics. Specifies // the frame of interest in the animation that's about to be rendered. diff --git a/chromium/cc/paint/skottie_serialization_history.cc b/chromium/cc/paint/skottie_serialization_history.cc index d7403547845..19004b4f51c 100644 --- a/chromium/cc/paint/skottie_serialization_history.cc +++ b/chromium/cc/paint/skottie_serialization_history.cc @@ -16,10 +16,9 @@ namespace cc { SkottieSerializationHistory::SkottieFrameDataId::SkottieFrameDataId( const SkottieFrameData& frame_data) - : paint_image_id(frame_data.image.stable_id()), - quality(frame_data.quality) { - DCHECK_NE(paint_image_id, PaintImage::kInvalidId); -} + : paint_image_id(frame_data.image ? frame_data.image.stable_id() + : PaintImage::kInvalidId), + quality(frame_data.quality) {} bool SkottieSerializationHistory::SkottieFrameDataId::operator==( const SkottieFrameDataId& other) const { diff --git a/chromium/cc/paint/skottie_serialization_history_unittest.cc b/chromium/cc/paint/skottie_serialization_history_unittest.cc index 4a6c0ea7ecd..64098b0871b 100644 --- a/chromium/cc/paint/skottie_serialization_history_unittest.cc +++ b/chromium/cc/paint/skottie_serialization_history_unittest.cc @@ -21,6 +21,7 @@ namespace cc { namespace { +using ::testing::Contains; using ::testing::IsEmpty; using ::testing::Pair; using ::testing::UnorderedElementsAre; @@ -90,6 +91,49 @@ TEST_F(SkottieSerializationHistoryTest, FilterNewSkottieFrameImages) { EXPECT_THAT(images, IsEmpty()); } +TEST_F(SkottieSerializationHistoryTest, HandlesEmptyImages) { + auto skottie = CreateSkottieFromString( + CreateCustomLottieDataWith2Assets("asset_a", "asset_b")); + PaintImage blank_image; + PaintImage image_1 = CreateBitmapImage(gfx::Size(10, 10)); + PaintImage image_2 = CreateBitmapImage(gfx::Size(20, 20)); + ; + + SkottieFrameDataMap images = { + {HashSkottieResourceId("asset_a"), + {blank_image, PaintFlags::FilterQuality::kMedium}}, + {HashSkottieResourceId("asset_b"), + {image_2, PaintFlags::FilterQuality::kMedium}}, + }; + history_.FilterNewSkottieFrameState(*skottie, images, empty_text_map); + EXPECT_THAT( + images, + Contains(Pair(HashSkottieResourceId("asset_a"), + SkottieFrameData( + {blank_image, PaintFlags::FilterQuality::kMedium})))); + + images = {{HashSkottieResourceId("asset_a"), + {image_1, PaintFlags::FilterQuality::kMedium}}}; + history_.FilterNewSkottieFrameState(*skottie, images, empty_text_map); + EXPECT_THAT( + images, + Contains(Pair( + HashSkottieResourceId("asset_a"), + SkottieFrameData({image_1, PaintFlags::FilterQuality::kMedium})))); + + images = {{HashSkottieResourceId("asset_a"), + {blank_image, PaintFlags::FilterQuality::kMedium}}}; + history_.FilterNewSkottieFrameState(*skottie, images, empty_text_map); + EXPECT_THAT( + images, + Contains(Pair(HashSkottieResourceId("asset_a"), + SkottieFrameData( + {blank_image, PaintFlags::FilterQuality::kMedium})))); + + history_.FilterNewSkottieFrameState(*skottie, images, empty_text_map); + EXPECT_THAT(images, IsEmpty()); +} + TEST_F(SkottieSerializationHistoryTest, FilterNewSkottieFrameText) { auto skottie = CreateSkottie(gfx::Size(10, 10), 1); diff --git a/chromium/cc/paint/skottie_wrapper.h b/chromium/cc/paint/skottie_wrapper.h index cbeece2c245..a7c4a7cf824 100644 --- a/chromium/cc/paint/skottie_wrapper.h +++ b/chromium/cc/paint/skottie_wrapper.h @@ -63,16 +63,13 @@ class CC_PAINT_EXPORT SkottieWrapper // immutable and does not change during SkottieWrapper's lifetime. virtual const base::flat_set<std::string>& GetTextNodeNames() const = 0; - // Returns the set of all text nodes in the animation, along with their - // corresponding current values. The nodes' values can only be updated via - // the |text_map| argument in Draw(). + // Returns a map from hashed animation node name to its current property + // value in the animation (see SkottieProperty.h). Some properties' values + // can be updated via its corresponding argument in Draw(). virtual SkottieTextPropertyValueMap GetCurrentTextPropertyValues() const = 0; - - // Returns the set of all transform nodes in the animation, along with their - // corresponding current values. The nodes' values are not updateable via - // Draw() like other properties simply because there is no use case yet. virtual SkottieTransformPropertyValueMap GetCurrentTransformPropertyValues() const = 0; + virtual SkottieColorMap GetCurrentColorPropertyValues() const = 0; // Returns all markers present in the animation. The returned list is // immutable and does not change during SkottieWrapper's lifetime. @@ -91,9 +88,9 @@ class CC_PAINT_EXPORT SkottieWrapper // The callback's output parameters have not been filled and will be // ignored by SkottieWrapper. In this case, SkottieWrapper will reuse the // frame data that was most recently provided for the given asset (it caches - // this internally). If no frame data has ever been provided for this asset, - // a null image will be passed to Skottie's Animation during Seek(); this - // is acceptable if there's no rendering. + // this internally). Note it is acceptable to set |image_out| to a null + // SkImage; Skottie will simply skip the image asset while rendering the + // rest of the frame. NO_UPDATE, }; // The callback's implementation must synchronously fill the output diff --git a/chromium/cc/paint/skottie_wrapper_impl.cc b/chromium/cc/paint/skottie_wrapper_impl.cc index 7345e2f1c84..703575304f0 100644 --- a/chromium/cc/paint/skottie_wrapper_impl.cc +++ b/chromium/cc/paint/skottie_wrapper_impl.cc @@ -14,6 +14,7 @@ #include "base/containers/flat_map.h" #include "base/hash/hash.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "base/trace_event/trace_event.h" @@ -46,117 +47,169 @@ class SkottieLogWriter : public skottie::Logger { } }; -class PropertyHandler final : public skottie::PropertyObserver { +// Methods for converting from a skottie::<Type>PropertyValue to its +// corresponding representation in Chromium that gets circulated through the +// graphics pipeline. +class SkottiePropertyConversions { public: - PropertyHandler() = default; - PropertyHandler(const PropertyHandler&) = delete; - PropertyHandler& operator=(const PropertyHandler&) = delete; - ~PropertyHandler() override = default; - - void ApplyColorMap(const SkottieColorMap& color_map) { - for (const auto& map_color : color_map) { - for (auto& handle : color_handles_[map_color.first]) { - DCHECK(handle); - handle->set(map_color.second); - } - } + // Convert skottie library representation to Chromium representation: + static SkColor ConvertToChromium( + const skottie::ColorPropertyValue& skottie_value) { + return skottie_value; + } + + static SkottieTextPropertyValue ConvertToChromium( + const skottie::TextPropertyValue& skottie_value) { + std::string text(skottie_value.fText.c_str()); + return SkottieTextPropertyValue(std::move(text), + gfx::SkRectToRectF(skottie_value.fBox)); } - void ApplyTextMap(const SkottieTextPropertyValueMap& text_map) { - for (const auto& [node_name_hash, new_text_val] : text_map) { - auto current_text_values_iter = current_text_values_.find(node_name_hash); - if (current_text_values_iter == current_text_values_.end()) { - LOG(WARNING) << "Encountered unknown text node with hash: " + static SkottieTransformPropertyValue ConvertToChromium( + const skottie::TransformPropertyValue& skottie_value) { + SkottieTransformPropertyValue output = { + /*position*/ gfx::SkPointToPointF(skottie_value.fPosition)}; + return output; + } + + // Convert Chromium representation to skottie library representation: + static void ConvertToSkottie(const SkColor& chromium_value, + skottie::ColorPropertyValue& skottie_value_out) { + skottie_value_out = chromium_value; + } + + static void ConvertToSkottie(const SkottieTextPropertyValue& chromium_value, + skottie::TextPropertyValue& skottie_value_out) { + skottie_value_out.fText.set(chromium_value.text().c_str()); + skottie_value_out.fBox = gfx::RectFToSkRect(chromium_value.box()); + } + + static void ConvertToSkottie( + const SkottieTransformPropertyValue& chromium_value, + skottie::TransformPropertyValue& skottie_value_out) { + NOTIMPLEMENTED() << "No use case yet for modifying transform properties"; + } +}; + +template <typename SkottiePropertyValueType, + typename SkottiePropertyHandleType, + typename ChromiumPropertyValueType> +class PropertyManager { + public: + PropertyManager() = default; + PropertyManager(const PropertyManager&) = delete; + PropertyManager& operator=(const PropertyManager&) = delete; + ~PropertyManager() = default; + + void OnNodeParsed( + const char node_name[], + const skottie::PropertyObserver::LazyHandle<SkottiePropertyHandleType>& + lh) { + if (!node_name) + return; + + node_names_.insert(node_name); + SkottieResourceIdHash node_name_hash = HashSkottieResourceId(node_name); + auto skottie_property_handle = lh(); + current_vals_as_chromium_.emplace( + node_name_hash, SkottiePropertyConversions::ConvertToChromium( + skottie_property_handle->get())); + skottie_property_handles_[node_name_hash].push_back( + std::move(skottie_property_handle)); + } + + void SetNewValues( + const base::flat_map<SkottieResourceIdHash, ChromiumPropertyValueType>& + new_vals_as_chromium) { + for (const auto& [node_name_hash, new_val_as_chromium] : + new_vals_as_chromium) { + auto iter = current_vals_as_chromium_.find(node_name_hash); + if (iter == current_vals_as_chromium_.end()) { + LOG(WARNING) << "Encountered unknown property node with hash: " << node_name_hash; continue; } - current_text_values_iter->second = new_text_val; - - for (auto& handle : text_handles_[node_name_hash]) { - DCHECK(handle); - skottie::TextPropertyValue current_text_val = handle->get(); - ConvertTextValueToSkottie(new_text_val, current_text_val); - handle->set(std::move(current_text_val)); + iter->second = new_val_as_chromium; + + for (auto& skottie_handle : skottie_property_handles_[node_name_hash]) { + DCHECK(skottie_handle); + SkottiePropertyValueType current_val_as_skottie = skottie_handle->get(); + SkottiePropertyConversions::ConvertToSkottie(new_val_as_chromium, + current_val_as_skottie); + skottie_handle->set(std::move(current_val_as_skottie)); } } } - const SkottieTextPropertyValueMap& current_text_values() const { - return current_text_values_; + const base::flat_set<std::string>& node_names() const { return node_names_; } + + const base::flat_map<SkottieResourceIdHash, ChromiumPropertyValueType> + current_vals_as_chromium() const { + return current_vals_as_chromium_; } - const SkottieTransformPropertyValueMap current_transform_values() const { - return current_transform_values_; + private: + base::flat_map<SkottieResourceIdHash, + std::vector<std::unique_ptr<SkottiePropertyHandleType>>> + skottie_property_handles_; + base::flat_set<std::string> node_names_; + base::flat_map<SkottieResourceIdHash, ChromiumPropertyValueType> + current_vals_as_chromium_; +}; + +using ColorPropertyManager = PropertyManager<skottie::ColorPropertyValue, + skottie::ColorPropertyHandle, + SkColor>; +using TextPropertyManager = PropertyManager<skottie::TextPropertyValue, + skottie::TextPropertyHandle, + SkottieTextPropertyValue>; +using TransformPropertyManager = + PropertyManager<skottie::TransformPropertyValue, + skottie::TransformPropertyHandle, + SkottieTransformPropertyValue>; + +class GlobalPropertyManager final : public skottie::PropertyObserver { + public: + GlobalPropertyManager() = default; + GlobalPropertyManager(const GlobalPropertyManager&) = delete; + GlobalPropertyManager& operator=(const GlobalPropertyManager&) = delete; + ~GlobalPropertyManager() override = default; + + ColorPropertyManager& color_property_manager() { + return color_property_manager_; } - const base::flat_set<std::string>& text_node_names() const { - return text_node_names_; + TextPropertyManager& text_property_manager() { + return text_property_manager_; + } + + TransformPropertyManager& transform_property_manager() { + return transform_property_manager_; } // skottie::PropertyObserver: void onColorProperty( const char node_name[], const LazyHandle<skottie::ColorPropertyHandle>& lh) override { - if (node_name) - color_handles_[HashSkottieResourceId(node_name)].push_back(lh()); + color_property_manager_.OnNodeParsed(node_name, lh); } void onTextProperty( const char node_name[], const LazyHandle<skottie::TextPropertyHandle>& lh) override { - if (!node_name) - return; - - text_node_names_.insert(node_name); - SkottieResourceIdHash node_name_hash = HashSkottieResourceId(node_name); - auto text_handle = lh(); - current_text_values_.emplace( - node_name_hash, ConvertTextValueToChromium(text_handle->get())); - text_handles_[node_name_hash].push_back(std::move(text_handle)); + text_property_manager_.OnNodeParsed(node_name, lh); } void onTransformProperty( const char node_name[], const LazyHandle<skottie::TransformPropertyHandle>& lh) override { - if (!node_name) - return; - - current_transform_values_.emplace( - HashSkottieResourceId(node_name), - ConvertTransformValueToChromium(lh()->get())); + transform_property_manager_.OnNodeParsed(node_name, lh); } private: - static SkottieTextPropertyValue ConvertTextValueToChromium( - const skottie::TextPropertyValue& value_in) { - std::string text(value_in.fText.c_str()); - return SkottieTextPropertyValue(std::move(text), - gfx::SkRectToRectF(value_in.fBox)); - } - - static void ConvertTextValueToSkottie( - const SkottieTextPropertyValue& value_in, - skottie::TextPropertyValue& value_out) { - value_out.fText.set(value_in.text().c_str()); - value_out.fBox = gfx::RectFToSkRect(value_in.box()); - } - - static SkottieTransformPropertyValue ConvertTransformValueToChromium( - const skottie::TransformPropertyValue& value_in) { - SkottieTransformPropertyValue output = { - /*position*/ gfx::SkPointToPointF(value_in.fPosition)}; - return output; - } - - base::flat_map<SkottieResourceIdHash, - std::vector<std::unique_ptr<skottie::ColorPropertyHandle>>> - color_handles_; - base::flat_map<SkottieResourceIdHash, - std::vector<std::unique_ptr<skottie::TextPropertyHandle>>> - text_handles_; - base::flat_set<std::string> text_node_names_; - SkottieTextPropertyValueMap current_text_values_; - SkottieTransformPropertyValueMap current_transform_values_; + ColorPropertyManager color_property_manager_; + TextPropertyManager text_property_manager_; + TransformPropertyManager transform_property_manager_; }; class MarkerStore : public skottie::MarkerObserver { @@ -212,19 +265,28 @@ class SkottieWrapperImpl : public SkottieWrapper { const base::flat_set<std::string>& GetTextNodeNames() const override LOCKS_EXCLUDED(lock_) { base::AutoLock lock(lock_); - return property_handler_->text_node_names(); + return property_manager_->text_property_manager().node_names(); } SkottieTextPropertyValueMap GetCurrentTextPropertyValues() const override LOCKS_EXCLUDED(lock_) { base::AutoLock lock(lock_); - return property_handler_->current_text_values(); + return property_manager_->text_property_manager() + .current_vals_as_chromium(); } SkottieTransformPropertyValueMap GetCurrentTransformPropertyValues() const override LOCKS_EXCLUDED(lock_) { base::AutoLock lock(lock_); - return property_handler_->current_transform_values(); + return property_manager_->transform_property_manager() + .current_vals_as_chromium(); + } + + SkottieColorMap GetCurrentColorPropertyValues() const override + LOCKS_EXCLUDED(lock_) { + base::AutoLock lock(lock_); + return property_manager_->color_property_manager() + .current_vals_as_chromium(); } const std::vector<SkottieMarker>& GetAllMarkers() const override { @@ -250,8 +312,8 @@ class SkottieWrapperImpl : public SkottieWrapper { LOCKS_EXCLUDED(lock_) { base::AutoLock lock(lock_); current_frame_data_cb_ = std::move(frame_data_cb); - property_handler_->ApplyColorMap(color_map); - property_handler_->ApplyTextMap(text_map); + property_manager_->color_property_manager().SetNewValues(color_map); + property_manager_->text_property_manager().SetNewValues(text_map); animation_->seek(t); animation_->render(canvas, &rect); } @@ -272,12 +334,12 @@ class SkottieWrapperImpl : public SkottieWrapper { base::span<const uint8_t> data, std::vector<uint8_t> raw_data, const sk_sp<SkottieMRUResourceProvider>& mru_resource_provider) - : property_handler_(sk_make_sp<PropertyHandler>()), + : property_manager_(sk_make_sp<GlobalPropertyManager>()), marker_store_(sk_make_sp<MarkerStore>()), animation_( skottie::Animation::Builder() .setLogger(sk_make_sp<SkottieLogWriter>()) - .setPropertyObserver(property_handler_) + .setPropertyObserver(property_manager_) .setResourceProvider(skresources::CachingResourceProvider::Make( mru_resource_provider)) .setMarkerObserver(marker_store_) @@ -305,7 +367,7 @@ class SkottieWrapperImpl : public SkottieWrapper { mutable base::Lock lock_; FrameDataCallback current_frame_data_cb_ GUARDED_BY(lock_); - sk_sp<PropertyHandler> property_handler_ GUARDED_BY(lock_); + sk_sp<GlobalPropertyManager> property_manager_ GUARDED_BY(lock_); const sk_sp<MarkerStore> marker_store_; sk_sp<skottie::Animation> animation_; diff --git a/chromium/cc/paint/skottie_wrapper_unittest.cc b/chromium/cc/paint/skottie_wrapper_unittest.cc index f45f625accf..469e2d9c186 100644 --- a/chromium/cc/paint/skottie_wrapper_unittest.cc +++ b/chromium/cc/paint/skottie_wrapper_unittest.cc @@ -185,6 +185,53 @@ TEST(SkottieWrapperTest, LoadsCorrectAssetsForSeek) { Mock::VerifyAndClearExpectations(&mock_callback); } +TEST(SkottieWrapperTest, LoadsColorNodes) { + auto skottie = CreateSkottieFromString(kLottieDataWithoutAssets1); + ASSERT_TRUE(skottie->is_valid()); + EXPECT_THAT( + skottie->GetCurrentColorPropertyValues(), + UnorderedElementsAre( + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color1Node), + kLottieDataWithoutAssets1Color1), + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color2Node), + kLottieDataWithoutAssets1Color2))); +} + +TEST(SkottieWrapperTest, SetsColorNodesWithDraw) { + auto skottie = CreateSkottieFromString(kLottieDataWithoutAssets1); + ASSERT_TRUE(skottie->is_valid()); + ::testing::NiceMock<MockCanvas> canvas; + + SkottieColorMap color_map = { + {HashSkottieResourceId(kLottieDataWithoutAssets1Color1Node), + SK_ColorYELLOW}, + {HashSkottieResourceId(kLottieDataWithoutAssets1Color2Node), + SK_ColorCYAN}}; + skottie->Draw(&canvas, /*t=*/0, SkRect::MakeWH(500, 500), + SkottieWrapper::FrameDataCallback(), color_map, + SkottieTextPropertyValueMap()); + EXPECT_THAT( + skottie->GetCurrentColorPropertyValues(), + UnorderedElementsAre( + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color1Node), + SK_ColorYELLOW), + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color2Node), + SK_ColorCYAN))); + + color_map = {{HashSkottieResourceId(kLottieDataWithoutAssets1Color2Node), + SK_ColorMAGENTA}}; + skottie->Draw(&canvas, /*t=*/0, SkRect::MakeWH(500, 500), + SkottieWrapper::FrameDataCallback(), color_map, + SkottieTextPropertyValueMap()); + EXPECT_THAT( + skottie->GetCurrentColorPropertyValues(), + UnorderedElementsAre( + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color1Node), + SK_ColorYELLOW), + Pair(HashSkottieResourceId(kLottieDataWithoutAssets1Color2Node), + SK_ColorMAGENTA))); +} + TEST(SkottieWrapperTest, LoadsTextNodes) { auto skottie = CreateSkottieFromTestDataDir(kLottieDataWith2TextFileName); ASSERT_TRUE(skottie->is_valid()); diff --git a/chromium/cc/paint/solid_color_analyzer.cc b/chromium/cc/paint/solid_color_analyzer.cc index a1d4a92d01e..73f38fc20ed 100644 --- a/chromium/cc/paint/solid_color_analyzer.cc +++ b/chromium/cc/paint/solid_color_analyzer.cc @@ -324,8 +324,8 @@ absl::optional<SkColor4f> SolidColorAnalyzer::DetermineIfSolidColor( if (++num_draw_ops > max_ops_to_analyze) return absl::nullopt; const DrawColorOp* color_op = static_cast<const DrawColorOp*>(op); - CheckIfSolidColor(canvas, SkColor4f::FromColor(color_op->color), - color_op->mode, &is_solid, &is_transparent, &color); + CheckIfSolidColor(canvas, color_op->color, color_op->mode, &is_solid, + &is_transparent, &color); break; } case PaintOpType::ClipRect: { diff --git a/chromium/cc/paint/solid_color_analyzer_unittest.cc b/chromium/cc/paint/solid_color_analyzer_unittest.cc index 26c50f99ad5..a343e1d4cc5 100644 --- a/chromium/cc/paint/solid_color_analyzer_unittest.cc +++ b/chromium/cc/paint/solid_color_analyzer_unittest.cc @@ -116,7 +116,7 @@ TEST_F(SolidColorAnalyzerTest, DrawOval) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); canvas()->drawOval(SkRect::MakeWH(100, 100), flags); EXPECT_FALSE(IsSolidColor()); } @@ -125,7 +125,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRect) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(200, 200); canvas()->clipRect(rect, SkClipOp::kIntersect, false); canvas()->drawRect(rect, flags); @@ -142,7 +142,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRRect) { Initialize(canvas_rect); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); canvas()->drawRRect(rrect, flags); EXPECT_EQ(color, GetColor()); } @@ -151,7 +151,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClipped) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(200, 200); canvas()->clipRect(SkRect::MakeWH(50, 50), SkClipOp::kIntersect, false); canvas()->drawRect(rect, flags); @@ -162,7 +162,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClippedDifference) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect drawRect = SkRect::MakeWH(200, 200); canvas()->clipRect(drawRect, SkClipOp::kIntersect, false); SkRect differenceRect = SkRect::MakeXYWH(50, 50, 200, 200); @@ -176,7 +176,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateNotSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(100, 100); canvas()->translate(1, 1); canvas()->drawRect(rect, flags); @@ -187,7 +187,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(101, 101); canvas()->translate(1, 1); canvas()->drawRect(rect, flags); @@ -206,7 +206,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeClear) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); flags.setBlendMode(SkBlendMode::kClear); SkRect rect = SkRect::MakeWH(200, 200); canvas()->drawRect(rect, flags); @@ -217,7 +217,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeSrcOver) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); flags.setBlendMode(SkBlendMode::kSrcOver); SkRect rect = SkRect::MakeWH(200, 200); canvas()->drawRect(rect, flags); @@ -228,7 +228,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectRotated) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(200, 200); canvas()->rotate(50); canvas()->drawRect(rect, flags); @@ -239,7 +239,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectScaledNotSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(200, 200); canvas()->scale(0.1f, 0.1f); canvas()->drawRect(rect, flags); @@ -250,7 +250,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectScaledSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(10, 10); canvas()->scale(10, 10); canvas()->drawRect(rect, flags); @@ -261,7 +261,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectFilterPaint) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); flags.setImageFilter(sk_make_sp<OffsetPaintFilter>(10, 10, nullptr)); SkRect rect = SkRect::MakeWH(200, 200); canvas()->drawRect(rect, flags); @@ -272,7 +272,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClipPath) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkPath path; path.moveTo(0, 0); @@ -291,7 +291,7 @@ TEST_F(SolidColorAnalyzerTest, DrawRectTranslucent) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(128, 128, 0, 0)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(100, 100); canvas()->drawRect(rect, flags); #if BUILDFLAG(IS_MAC) @@ -307,11 +307,11 @@ TEST_F(SolidColorAnalyzerTest, DrawRectTranslucentOverNonSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(100, 50); canvas()->drawRect(rect, flags); color = SkColor4f::FromColor(SkColorSetARGB(128, 0, 128, 0)); - flags.setColor4f(color); + flags.setColor(color); rect = SkRect::MakeWH(100, 100); canvas()->drawRect(rect, flags); EXPECT_FALSE(IsSolidColor(2 /* max_ops_to_analyze */)); @@ -321,11 +321,11 @@ TEST_F(SolidColorAnalyzerTest, DrawRectOpaqueOccludesNonSolid) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(100, 50); canvas()->drawRect(rect, flags); color = SkColor4f::FromColor(SkColorSetARGB(255, 0, 128, 0)); - flags.setColor4f(color); + flags.setColor(color); rect = SkRect::MakeWH(100, 100); canvas()->drawRect(rect, flags); EXPECT_EQ(color, GetColor(2 /* max_ops_to_analyze */)); @@ -335,11 +335,11 @@ TEST_F(SolidColorAnalyzerTest, DrawRectSolidWithSrcOverBlending) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(64, 40, 50, 60)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(100, 100); canvas()->drawRect(rect, flags); color = SkColor4f::FromColor(SkColorSetARGB(128, 10, 20, 30)); - flags.setColor4f(color); + flags.setColor(color); rect = SkRect::MakeWH(100, 100); canvas()->drawRect(rect, flags); #if BUILDFLAG(IS_MAC) @@ -357,7 +357,7 @@ TEST_F(SolidColorAnalyzerTest, SaveLayer) { Initialize(); PaintFlags flags; SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33)); - flags.setColor4f(color); + flags.setColor(color); SkRect rect = SkRect::MakeWH(200, 200); canvas()->saveLayer(&rect, &flags); @@ -379,7 +379,7 @@ TEST_F(SolidColorAnalyzerTest, ClipRRectCoversCanvas) { int canvas_size = 255; gfx::Rect canvas_rect(canvas_size, canvas_size); PaintFlags flags; - flags.setColor4f(SkColors::kWhite); + flags.setColor(SkColors::kWhite); struct { SkVector offset; diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc index f8f7984e8db..af89bbfcece 100644 --- a/chromium/cc/paint/transfer_cache_unittest.cc +++ b/chromium/cc/paint/transfer_cache_unittest.cc @@ -49,8 +49,7 @@ class TransferCacheTest : public testing::Test { context_ = std::make_unique<gpu::RasterInProcessContext>(); auto result = context_->Initialize( viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs, - gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_, &image_factory_, - /*gpu_channel_manager_delegate=*/nullptr, nullptr, nullptr); + gpu::SharedMemoryLimits(), &image_factory_, nullptr, nullptr); ASSERT_EQ(result, gpu::ContextResult::kSuccess); ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster); diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc index a404b098d21..a7065c6b83f 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc @@ -90,7 +90,7 @@ class BitmapRasterBufferImpl : public RasterBuffer { // `pixels_` is not a raw_ptr<...> for performance reasons: pointee is never // protected by BackupRefPtr, because the pointer comes either from using // `mmap`, MapViewOfFile or base::AllocPages directly. - void* const pixels_; + RAW_PTR_EXCLUSION void* const pixels_; bool resource_has_previous_content_; }; diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc index f88bec234b7..bf0d9d7b2d4 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.cc +++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc @@ -12,6 +12,7 @@ #include <vector> #include "base/bits.h" +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_macros.h" @@ -379,7 +380,7 @@ void GpuRasterBufferProvider::RasterBufferImpl::RasterizeSource( // If playback_settings.msaa_sample_count <= 0, the MSAA is not used. It is // equivalent to MSAA sample count 1. uint32_t sample_count = - std::clamp(playback_settings.msaa_sample_count, 1, 64); + base::clamp(playback_settings.msaa_sample_count, 1, 64); UMA_HISTOGRAM_CUSTOM_COUNTS("Gpu.Rasterization.Raster.MSAASampleCountLog2", base::bits::Log2Floor(sample_count), 0, 7, 7); // With Raw Draw, the framebuffer will be the rasterization target. It cannot @@ -388,10 +389,12 @@ void GpuRasterBufferProvider::RasterBufferImpl::RasterizeSource( bool is_raw_draw_backing = client_->is_using_raw_draw_ && !backing_->overlay_candidate; bool use_lcd_text = playback_settings.use_lcd_text && !is_raw_draw_backing; + ri->BeginRasterCHROMIUM( raster_source->background_color(), mailbox_needs_clear, playback_settings.msaa_sample_count, msaa_mode, use_lcd_text, playback_settings.visible, color_space_, backing_->mailbox.name); + gfx::Vector2dF recording_to_raster_scale = transform.scale(); recording_to_raster_scale.Scale(1 / raster_source->recording_scale_factor()); gfx::Size content_size = raster_source->GetContentSize(transform.scale()); diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc index 31df8af1b09..ca84866c0c5 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc @@ -413,7 +413,7 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( // Create staging shared image. if (staging_buffer->mailbox.IsZero()) { - const uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER; + const uint32_t usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE; staging_buffer->mailbox = sii->CreateSharedImage( staging_buffer->gpu_memory_buffer.get(), gpu_memory_buffer_manager_, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage); @@ -468,7 +468,9 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( resource_size.height()); SkBitmap bitmap; if (bitmap.tryAllocPixels(dst_info, clear_bytes_per_row)) { - bitmap.eraseColor(raster_source->background_color()); + // SkBitmap.cpp doesn't yet have an interface for SkColor4fs + // https://bugs.chromium.org/p/skia/issues/detail?id=13329 + bitmap.eraseColor(raster_source->background_color().toSkColor()); ri->WritePixels(*mailbox, 0, 0, mailbox_texture_target, clear_bytes_per_row, dst_info, bitmap.getPixels()); } diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc index 78cd768d485..f6c39937b46 100644 --- a/chromium/cc/raster/raster_buffer_provider_perftest.cc +++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc @@ -40,12 +40,6 @@ namespace { class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub { // Overridden from gpu::gles2::GLES2Interface: - GLuint CreateImageCHROMIUM(ClientBuffer buffer, - GLsizei width, - GLsizei height, - GLenum internalformat) override { - return 1u; - } void GenBuffers(GLsizei n, GLuint* buffers) override { for (GLsizei i = 0; i < n; ++i) buffers[i] = 1u; diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc index 40ff7b1cb6e..42f1a147ec5 100644 --- a/chromium/cc/raster/raster_source.cc +++ b/chromium/cc/raster/raster_source.cc @@ -128,7 +128,7 @@ void RasterSource::PlaybackDisplayListToCanvas( } bool RasterSource::PerformSolidColorAnalysis(gfx::Rect layer_rect, - SkColor* color) const { + SkColor4f* color) const { TRACE_EVENT0("cc", "RasterSource::PerformSolidColorAnalysis"); layer_rect.Intersect(gfx::Rect(size_)); @@ -183,7 +183,7 @@ bool RasterSource::IsSolidColor() const { SkColor RasterSource::GetSolidColor() const { DCHECK(IsSolidColor()); - return solid_color_; + return solid_color_.toSkColor(); } bool RasterSource::HasRecordings() const { diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h index f8ab19ff57c..9e0fc1b719e 100644 --- a/chromium/cc/raster/raster_source.h +++ b/chromium/cc/raster/raster_source.h @@ -80,7 +80,8 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { // Returns whether the given rect at given scale is of solid color in // this raster source, as well as the solid color value. - bool PerformSolidColorAnalysis(gfx::Rect content_rect, SkColor* color) const; + bool PerformSolidColorAnalysis(gfx::Rect content_rect, + SkColor4f* color) const; // Returns true iff the whole raster source is of solid color. bool IsSolidColor() const; @@ -121,7 +122,7 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { float recording_scale_factor() const { return recording_scale_factor_; } - SkColor background_color() const { return background_color_; } + SkColor4f background_color() const { return background_color_; } bool requires_clear() const { return requires_clear_; } @@ -163,10 +164,10 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { // These members are const as this raster source may be in use on another // thread and so should not be touched after construction. const scoped_refptr<DisplayItemList> display_list_; - const SkColor background_color_; + const SkColor4f background_color_; const bool requires_clear_; const bool is_solid_color_; - const SkColor solid_color_; + const SkColor4f solid_color_; const gfx::Rect recorded_viewport_; const gfx::Size size_; const int slow_down_raster_scale_factor_for_debug_; diff --git a/chromium/cc/raster/raster_source_unittest.cc b/chromium/cc/raster/raster_source_unittest.cc index 7085096822b..dd16a6526d4 100644 --- a/chromium/cc/raster/raster_source_unittest.cc +++ b/chromium/cc/raster/raster_source_unittest.cc @@ -51,7 +51,7 @@ TEST(RasterSourceTest, AnalyzeIsSolidUnscaled) { solid_flags.setColor(solid_color); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; PaintFlags non_solid_flags; bool is_solid_color = false; non_solid_flags.setColor(non_solid_color); @@ -68,7 +68,7 @@ TEST(RasterSourceTest, AnalyzeIsSolidUnscaled) { gfx::Rect rect(x, y, 100, 100); is_solid_color = raster->PerformSolidColorAnalysis(rect, &color); EXPECT_TRUE(is_solid_color) << rect.ToString(); - EXPECT_COLOR_EQ(solid_color, color) << rect.ToString(); + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << rect.ToString(); } } @@ -78,35 +78,35 @@ TEST(RasterSourceTest, AnalyzeIsSolidUnscaled) { recording_source->Rerecord(); raster = recording_source->CreateRasterSource(); - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), &color); EXPECT_FALSE(is_solid_color); - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(100, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color); - EXPECT_COLOR_EQ(solid_color, color); + EXPECT_COLOR_EQ(solid_color, color.toSkColor()); // Boundaries should be clipped. - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color); - EXPECT_COLOR_EQ(solid_color, color); + EXPECT_COLOR_EQ(solid_color, color.toSkColor()); - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(0, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color); - EXPECT_COLOR_EQ(solid_color, color); + EXPECT_COLOR_EQ(solid_color, color.toSkColor()); - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(350, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color); - EXPECT_COLOR_EQ(solid_color, color); + EXPECT_COLOR_EQ(solid_color, color.toSkColor()); } TEST(RasterSourceTest, AnalyzeIsSolidScaled) { @@ -123,7 +123,7 @@ TEST(RasterSourceTest, AnalyzeIsSolidScaled) { solid_flags.setColor(solid_color); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; PaintFlags non_solid_flags; bool is_solid_color = false; non_solid_flags.setColor(non_solid_color); @@ -142,7 +142,7 @@ TEST(RasterSourceTest, AnalyzeIsSolidScaled) { is_solid_color = raster->PerformSolidColorAnalysis(rect, &color); EXPECT_TRUE(is_solid_color) << rect.ToString() << " recording_scale: " << recording_scale; - EXPECT_COLOR_EQ(solid_color, color) + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << rect.ToString() << " recording_scale: " << recording_scale; } } @@ -155,43 +155,43 @@ TEST(RasterSourceTest, AnalyzeIsSolidScaled) { recording_source->Rerecord(); raster = recording_source->CreateRasterSource(); - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), &color); EXPECT_FALSE(is_solid_color) << " recording_scale: " << recording_scale; - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 51, 51), &color); EXPECT_FALSE(is_solid_color) << " recording_scale: " << recording_scale; - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(51, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color) << " recording_scale: " << recording_scale; - EXPECT_COLOR_EQ(solid_color, color) + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << " recording_scale: " << recording_scale; // Boundaries should be clipped. - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color) << " recording_scale: " << recording_scale; - EXPECT_COLOR_EQ(solid_color, color) + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << " recording_scale: " << recording_scale; - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(0, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color) << " recording_scale: " << recording_scale; - EXPECT_COLOR_EQ(solid_color, color) + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << " recording_scale: " << recording_scale; - color = SK_ColorTRANSPARENT; + color = SkColors::kTransparent; is_solid_color = raster->PerformSolidColorAnalysis( gfx::Rect(350, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color) << " recording_scale: " << recording_scale; - EXPECT_COLOR_EQ(solid_color, color) + EXPECT_COLOR_EQ(solid_color, color.toSkColor()) << " recording_scale: " << recording_scale; } } @@ -268,7 +268,7 @@ TEST(RasterSourceTest, RasterFullContents) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorBLACK); + recording_source->SetBackgroundColor(SkColors::kBlack); // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. @@ -302,7 +302,7 @@ TEST(RasterSourceTest, RasterFullContents) { SkBitmap bitmap; bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height()); SkCanvas canvas(bitmap, SkSurfaceProps{}); - canvas.clear(SK_ColorTRANSPARENT); + canvas.clear(SkColors::kTransparent); raster->PlaybackToCanvas( &canvas, content_bounds, canvas_rect, canvas_rect, @@ -333,7 +333,7 @@ TEST(RasterSourceTest, RasterFullContentsWithRasterTranslation) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorBLACK); + recording_source->SetBackgroundColor(SkColors::kBlack); // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. @@ -363,7 +363,7 @@ TEST(RasterSourceTest, RasterFullContentsWithRasterTranslation) { SkBitmap bitmap; bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height()); SkCanvas canvas(bitmap, SkSurfaceProps{}); - canvas.clear(SK_ColorTRANSPARENT); + canvas.clear(SkColors::kTransparent); raster->PlaybackToCanvas( &canvas, content_bounds, canvas_rect, canvas_rect, @@ -393,7 +393,7 @@ TEST(RasterSourceTest, RasterPartialContents) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorGREEN); + recording_source->SetBackgroundColor(SkColors::kGreen); // First record everything as white. PaintFlags white_flags; @@ -467,7 +467,7 @@ TEST(RasterSourceTest, RasterPartialContentsWithRasterTranslation) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorGREEN); + recording_source->SetBackgroundColor(SkColors::kGreen); // First record everything as white. PaintFlags white_flags; @@ -558,7 +558,7 @@ TEST(RasterSourceTest, RasterPartialClear) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorGREEN); + recording_source->SetBackgroundColor(SkColors::kGreen); recording_source->SetRequiresClear(true); // First record everything as white. @@ -596,7 +596,7 @@ TEST(RasterSourceTest, RasterPartialClear) { std::unique_ptr<FakeRecordingSource> recording_source_light = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source_light->SetBackgroundColor(SK_ColorGREEN); + recording_source_light->SetBackgroundColor(SkColors::kGreen); recording_source_light->SetRequiresClear(true); // Record everything as a slightly lighter white. @@ -633,7 +633,7 @@ TEST(RasterSourceTest, RasterContentsTransparent) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->SetBackgroundColor(SK_ColorTRANSPARENT); + recording_source->SetBackgroundColor(SkColors::kTransparent); recording_source->SetRequiresClear(true); recording_source->Rerecord(); diff --git a/chromium/cc/raster/task_graph_work_queue.cc b/chromium/cc/raster/task_graph_work_queue.cc index 1ca3c67c2a9..707a1490983 100644 --- a/chromium/cc/raster/task_graph_work_queue.cc +++ b/chromium/cc/raster/task_graph_work_queue.cc @@ -13,6 +13,7 @@ #include <utility> #include "base/containers/contains.h" +#include "base/memory/raw_ptr_exclusion.h" #include "base/trace_event/trace_event.h" namespace cc { @@ -96,14 +97,14 @@ class DependentIterator { private: // `graph_` and `task_` are not a raw_ptr<...> for performance reasons (based // on analysis of sampling profiler data and tab_search:top100:2020). - TaskGraph* graph_; - const Task* task_; + RAW_PTR_EXCLUSION TaskGraph* graph_; + RAW_PTR_EXCLUSION const Task* task_; size_t current_index_; // `current_node_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - TaskGraph::Node* current_node_; + RAW_PTR_EXCLUSION TaskGraph::Node* current_node_; }; } // namespace diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index db52cf6d60a..5ff92dc3acc 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -339,7 +339,9 @@ bool ResourcePool::PrepareForExport(const InUsePoolResource& in_use_resource) { gpu_backing->mailbox, GL_LINEAR, gpu_backing->texture_target, gpu_backing->mailbox_sync_token, resource->size(), gpu_backing->overlay_candidate); - transferable.read_lock_fences_enabled = gpu_backing->wait_on_fence_required; + if (gpu_backing->wait_on_fence_required) + transferable.synchronization_type = + viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted; } else { transferable = viz::TransferableResource::MakeSoftware( resource->software_backing()->shared_bitmap_id, resource->size(), @@ -661,9 +663,8 @@ void ResourcePool::PoolResource::OnMemoryDump( dump->AddScalar(MemoryAllocatorDump::kNameSize, MemoryAllocatorDump::kUnitsBytes, total_bytes); - if (is_free) { - dump->AddScalar("free_size", MemoryAllocatorDump::kUnitsBytes, total_bytes); - } + uint64_t free_size = is_free ? total_bytes : 0u; + dump->AddScalar("free_size", MemoryAllocatorDump::kUnitsBytes, free_size); } } // namespace cc diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h index 3aedcd75035..a75b2e626de 100644 --- a/chromium/cc/resources/resource_pool.h +++ b/chromium/cc/resources/resource_pool.h @@ -202,7 +202,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { // `resource_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - PoolResource* resource_ = nullptr; + RAW_PTR_EXCLUSION PoolResource* resource_ = nullptr; }; // When holding gpu resources, the |context_provider| should be non-null, @@ -392,7 +392,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { } private: - ResourcePool* const resource_pool_; + const raw_ptr<ResourcePool> resource_pool_; const size_t unique_id_; const gfx::Size size_; const viz::ResourceFormat format_; diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc index 24d04f3fbfd..45104e75a1c 100644 --- a/chromium/cc/resources/resource_pool_unittest.cc +++ b/chromium/cc/resources/resource_pool_unittest.cc @@ -722,7 +722,9 @@ TEST_F(ResourcePoolTest, MetadataSentToDisplayCompositor) { EXPECT_EQ(transfer[0].mailbox_holder.sync_token, sync_token); EXPECT_EQ(transfer[0].mailbox_holder.texture_target, target); EXPECT_EQ(transfer[0].format, format); - EXPECT_TRUE(transfer[0].read_lock_fences_enabled); + EXPECT_EQ( + transfer[0].synchronization_type, + viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted); EXPECT_TRUE(transfer[0].is_overlay_candidate); resource_pool_->ReleaseResource(std::move(resource)); diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index 3be3099800c..0bc092faf29 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -74,11 +74,13 @@ void Scheduler::Stop() { void Scheduler::SetNeedsImplSideInvalidation( bool needs_first_draw_on_activation) { - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), - "Scheduler::SetNeedsImplSideInvalidation", - "needs_first_draw_on_activation", - needs_first_draw_on_activation); - state_machine_.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); + { + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), + "Scheduler::SetNeedsImplSideInvalidation", + "needs_first_draw_on_activation", + needs_first_draw_on_activation); + state_machine_.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); + } ProcessScheduledActions(); } @@ -107,6 +109,10 @@ void Scheduler::NotifyReadyToActivate() { ProcessScheduledActions(); } +bool Scheduler::IsReadyToActivate() { + return state_machine_.IsReadyToActivate(); +} + void Scheduler::NotifyReadyToDraw() { // Future work might still needed for crbug.com/352894. state_machine_.NotifyReadyToDraw(); @@ -175,10 +181,16 @@ void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token, base::Microseconds(1), base::Milliseconds(50), 50); } - compositor_frame_reporting_controller_->DidSubmitCompositorFrame( - frame_token, submit_time, begin_main_frame_args_.frame_id, - last_activate_origin_frame_args_.frame_id, std::move(events_metrics), - has_missing_content); + // Hardware and software draw may occur at the same frame simultaneously for + // Android WebView. There is no need to call DidSubmitCompositorFrame here for + // software draw. + if (!settings_.using_synchronous_renderer_compositor || + !state_machine_.resourceless_draw()) { + compositor_frame_reporting_controller_->DidSubmitCompositorFrame( + frame_token, submit_time, begin_main_frame_args_.frame_id, + last_activate_origin_frame_args_.frame_id, std::move(events_metrics), + has_missing_content); + } state_machine_.DidSubmitCompositorFrame(); // There is no need to call ProcessScheduledActions here because @@ -205,28 +217,27 @@ void Scheduler::SetTreePrioritiesAndScrollState( void Scheduler::NotifyReadyToCommit( std::unique_ptr<BeginMainFrameMetrics> details) { - TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); - compositor_timing_history_->NotifyReadyToCommit(); - compositor_frame_reporting_controller_->NotifyReadyToCommit( - std::move(details)); - state_machine_.NotifyReadyToCommit(); + { + TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); + compositor_timing_history_->NotifyReadyToCommit(); + compositor_frame_reporting_controller_->NotifyReadyToCommit( + std::move(details)); + state_machine_.NotifyReadyToCommit(); + } ProcessScheduledActions(); } -void Scheduler::DidCommit() { - compositor_timing_history_->DidCommit(); - compositor_frame_reporting_controller_->DidCommit(); -} - void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) { - TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason", - CommitEarlyOutReasonToString(reason)); - compositor_timing_history_->BeginMainFrameAborted(); - auto frame_id = last_dispatched_begin_main_frame_args_.frame_id; - compositor_frame_reporting_controller_->BeginMainFrameAborted(frame_id, - reason); - - state_machine_.BeginMainFrameAborted(reason); + { + TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason", + CommitEarlyOutReasonToString(reason)); + compositor_timing_history_->BeginMainFrameAborted(); + auto frame_id = last_dispatched_begin_main_frame_args_.frame_id; + compositor_frame_reporting_controller_->BeginMainFrameAborted(frame_id, + reason); + + state_machine_.BeginMainFrameAborted(reason); + } ProcessScheduledActions(); } @@ -247,18 +258,22 @@ void Scheduler::DidPresentCompositorFrame( } void Scheduler::DidLoseLayerTreeFrameSink() { - TRACE_EVENT0("cc", "Scheduler::DidLoseLayerTreeFrameSink"); - state_machine_.DidLoseLayerTreeFrameSink(); - UpdateCompositorTimingHistoryRecordingEnabled(); + { + TRACE_EVENT0("cc", "Scheduler::DidLoseLayerTreeFrameSink"); + state_machine_.DidLoseLayerTreeFrameSink(); + UpdateCompositorTimingHistoryRecordingEnabled(); + } ProcessScheduledActions(); } void Scheduler::DidCreateAndInitializeLayerTreeFrameSink() { - TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeLayerTreeFrameSink"); - DCHECK(!observing_begin_frame_source_); - DCHECK(!begin_impl_frame_deadline_timer_.IsRunning()); - state_machine_.DidCreateAndInitializeLayerTreeFrameSink(); - UpdateCompositorTimingHistoryRecordingEnabled(); + { + TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeLayerTreeFrameSink"); + DCHECK(!observing_begin_frame_source_); + DCHECK(!begin_impl_frame_deadline_timer_.IsRunning()); + state_machine_.DidCreateAndInitializeLayerTreeFrameSink(); + UpdateCompositorTimingHistoryRecordingEnabled(); + } ProcessScheduledActions(); } @@ -356,9 +371,11 @@ void Scheduler::PostPendingBeginFrameTask() { void Scheduler::OnBeginFrameSourcePausedChanged(bool paused) { if (state_machine_.begin_frame_source_paused() == paused) return; - TRACE_EVENT_INSTANT1("cc", "Scheduler::SetBeginFrameSourcePaused", - TRACE_EVENT_SCOPE_THREAD, "paused", paused); - state_machine_.SetBeginFrameSourcePaused(paused); + { + TRACE_EVENT_INSTANT1("cc", "Scheduler::SetBeginFrameSourcePaused", + TRACE_EVENT_SCOPE_THREAD, "paused", paused); + state_machine_.SetBeginFrameSourcePaused(paused); + } ProcessScheduledActions(); } @@ -763,24 +780,26 @@ void Scheduler::ScheduleBeginImplFrameDeadline() { } void Scheduler::OnBeginImplFrameDeadline() { - TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline"); - begin_impl_frame_deadline_timer_.Stop(); - // We split the deadline actions up into two phases so the state machine - // has a chance to trigger actions that should occur durring and after - // the deadline separately. For example: - // * Sending the BeginMainFrame will not occur after the deadline in - // order to wait for more user-input before starting the next commit. - // * Creating a new OuputSurface will not occur during the deadline in - // order to allow the state machine to "settle" first. - compositor_timing_history_->RecordDeadlineMode(deadline_mode_); - if (!settings_.using_synchronous_renderer_compositor) { - compositor_timing_history_->WillFinishImplFrame( - state_machine_.needs_redraw()); - compositor_frame_reporting_controller_->OnFinishImplFrame( - begin_main_frame_args_.frame_id); - } + { + TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline"); + begin_impl_frame_deadline_timer_.Stop(); + // We split the deadline actions up into two phases so the state machine + // has a chance to trigger actions that should occur during and after + // the deadline separately. For example: + // * Sending the BeginMainFrame will not occur after the deadline in + // order to wait for more user-input before starting the next commit. + // * Creating a new OutputSurface will not occur during the deadline in + // order to allow the state machine to "settle" first. + compositor_timing_history_->RecordDeadlineMode(deadline_mode_); + if (!settings_.using_synchronous_renderer_compositor) { + compositor_timing_history_->WillFinishImplFrame( + state_machine_.needs_redraw()); + compositor_frame_reporting_controller_->OnFinishImplFrame( + begin_main_frame_args_.frame_id); + } - state_machine_.OnBeginImplFrameDeadline(); + state_machine_.OnBeginImplFrameDeadline(); + } ProcessScheduledActions(); if (settings_.using_synchronous_renderer_compositor) @@ -817,6 +836,13 @@ void Scheduler::DrawForced() { bool drawing_with_new_active_tree = state_machine_.active_tree_needs_first_draw() && !state_machine_.previous_pending_tree_was_impl_side(); + if (drawing_with_new_active_tree) { + TRACE_EVENT_WITH_FLOW1( + "viz,benchmark", "Graphics.Pipeline.DrawForced", + TRACE_ID_GLOBAL(last_activate_origin_frame_args().trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "trace_id", + last_activate_origin_frame_args().trace_id); + } compositor_timing_history_->WillDraw(); state_machine_.WillDraw(); DrawResult result = client_->ScheduledActionDrawForced(); @@ -826,9 +852,11 @@ void Scheduler::DrawForced() { } void Scheduler::SetDeferBeginMainFrame(bool defer_begin_main_frame) { - TRACE_EVENT1("cc", "Scheduler::SetDeferBeginMainFrame", - "defer_begin_main_frame", defer_begin_main_frame); - state_machine_.SetDeferBeginMainFrame(defer_begin_main_frame); + { + TRACE_EVENT1("cc", "Scheduler::SetDeferBeginMainFrame", + "defer_begin_main_frame", defer_begin_main_frame); + state_machine_.SetDeferBeginMainFrame(defer_begin_main_frame); + } ProcessScheduledActions(); } @@ -881,15 +909,20 @@ void Scheduler::ProcessScheduledActions() { state_machine_.WillNotifyBeginMainFrameNotExpectedSoon(); BeginMainFrameNotExpectedSoon(); break; - case SchedulerStateMachine::Action::COMMIT: { - bool commit_has_no_updates = false; - state_machine_.WillCommit(commit_has_no_updates); + case SchedulerStateMachine::Action::COMMIT: + state_machine_.WillCommit(/*commit_had_no_updates=*/false); compositor_timing_history_->WillCommit(); compositor_frame_reporting_controller_->WillCommit(); client_->ScheduledActionCommit(); + compositor_timing_history_->DidCommit(); + compositor_frame_reporting_controller_->DidCommit(); + state_machine_.DidCommit(); last_commit_origin_frame_args_ = last_dispatched_begin_main_frame_args_; break; - } + case SchedulerStateMachine::Action::POST_COMMIT: + client_->ScheduledActionPostCommit(); + state_machine_.DidPostCommit(); + break; case SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE: compositor_timing_history_->WillActivate(); compositor_frame_reporting_controller_->WillActivate(); @@ -911,12 +944,11 @@ void Scheduler::ProcessScheduledActions() { case SchedulerStateMachine::Action::DRAW_FORCED: DrawForced(); break; - case SchedulerStateMachine::Action::DRAW_ABORT: { + case SchedulerStateMachine::Action::DRAW_ABORT: // No action is actually performed, but this allows the state machine to // drain the pipeline without actually drawing. state_machine_.AbortDraw(); break; - } case SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION: state_machine_.WillBeginLayerTreeFrameSinkCreation(); client_->ScheduledActionBeginLayerTreeFrameSinkCreation(); @@ -925,12 +957,11 @@ void Scheduler::ProcessScheduledActions() { state_machine_.WillPrepareTiles(); client_->ScheduledActionPrepareTiles(); break; - case SchedulerStateMachine::Action::INVALIDATE_LAYER_TREE_FRAME_SINK: { + case SchedulerStateMachine::Action::INVALIDATE_LAYER_TREE_FRAME_SINK: state_machine_.WillInvalidateLayerTreeFrameSink(); client_->ScheduledActionInvalidateLayerTreeFrameSink( state_machine_.RedrawPending()); break; - } } } while (action != SchedulerStateMachine::Action::NONE); diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h index 179b0e4202c..bf83e8447a7 100644 --- a/chromium/cc/scheduler/scheduler.h +++ b/chromium/cc/scheduler/scheduler.h @@ -67,6 +67,7 @@ class SchedulerClient { // compositor thread, which allows Compositor thread to update its layer tree // to match the state of the layer tree on the main thread. virtual void ScheduledActionCommit() = 0; + virtual void ScheduledActionPostCommit() = 0; virtual void ScheduledActionActivateSyncTree() = 0; virtual void ScheduledActionBeginLayerTreeFrameSinkCreation() = 0; virtual void ScheduledActionPrepareTiles() = 0; @@ -132,6 +133,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { // pending_tree, call this method to notify that this pending tree is ready to // be activated, that is to be copied to the active tree. void NotifyReadyToActivate(); + bool IsReadyToActivate(); void NotifyReadyToDraw(); void SetBeginFrameSource(viz::BeginFrameSource* source); @@ -176,6 +178,10 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { // new tree can be activated. void SetNeedsImplSideInvalidation(bool needs_first_draw_on_activation); + bool pending_tree_is_ready_for_activation() const { + return state_machine_.pending_tree_is_ready_for_activation(); + } + // Drawing should result in submitting a CompositorFrame to the // LayerTreeFrameSink and then calling this. void DidSubmitCompositorFrame(uint32_t frame_token, @@ -195,7 +201,6 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { // main thread updates are completed to signal it is ready for the commmit. void NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details); void BeginMainFrameAborted(CommitEarlyOutReason reason); - void DidCommit(); // In the PrepareTiles step, compositor thread divides the layers into tiles // to reduce cost of raster large layers. Then, each tile is rastered by a @@ -262,6 +267,9 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { const viz::BeginFrameArgs& last_dispatched_begin_main_frame_args() const { return last_dispatched_begin_main_frame_args_; } + const viz::BeginFrameArgs& last_commit_origin_frame_args() const { + return last_commit_origin_frame_args_; + } const viz::BeginFrameArgs& last_activate_origin_frame_args() const { return last_activate_origin_frame_args_; } diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index 0e49dca023e..0f9872b52eb 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -167,6 +167,8 @@ SchedulerStateMachine::ActionToProtozeroEnum(Action action) { case Action::SEND_BEGIN_MAIN_FRAME: return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_SEND_BEGIN_MAIN_FRAME; case Action::COMMIT: + case Action::POST_COMMIT: + // TODO(szager): Add CC_SCHEDULER_ACTION_POST_COMMIT to perfetto return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_COMMIT; case Action::ACTIVATE_SYNC_TREE: return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_ACTIVATE_SYNC_TREE; @@ -621,6 +623,20 @@ bool SchedulerStateMachine::ShouldCommit() const { return true; } +void SchedulerStateMachine::DidCommit() { + DCHECK(!needs_post_commit_); + needs_post_commit_ = true; +} + +bool SchedulerStateMachine::ShouldRunPostCommit() const { + return needs_post_commit_; +} + +void SchedulerStateMachine::DidPostCommit() { + DCHECK(needs_post_commit_); + needs_post_commit_ = false; +} + bool SchedulerStateMachine::ShouldPrepareTiles() const { // In full-pipeline mode, we need to prepare tiles ASAP to ensure that we // don't get stuck. @@ -662,6 +678,10 @@ bool SchedulerStateMachine::ShouldInvalidateLayerTreeFrameSink() const { } SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { + if (ShouldSendBeginMainFrame()) + return Action::SEND_BEGIN_MAIN_FRAME; + if (ShouldRunPostCommit()) + return Action::POST_COMMIT; if (ShouldActivateSyncTree()) return Action::ACTIVATE_SYNC_TREE; if (ShouldCommit()) @@ -675,8 +695,6 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { else return Action::DRAW_IF_POSSIBLE; } - if (ShouldSendBeginMainFrame()) - return Action::SEND_BEGIN_MAIN_FRAME; if (ShouldPerformImplSideInvalidation()) return Action::PERFORM_IMPL_SIDE_INVALIDATION; if (ShouldPrepareTiles()) @@ -1436,8 +1454,7 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) { SetNeedsBeginMainFrame(); return; case CommitEarlyOutReason::FINISHED_NO_UPDATES: - bool commit_has_no_updates = true; - WillCommit(commit_has_no_updates); + WillCommit(/*commit_had_no_updates=*/true); return; } } @@ -1469,6 +1486,10 @@ bool SchedulerStateMachine::NotifyReadyToActivate() { return true; } +bool SchedulerStateMachine::IsReadyToActivate() { + return pending_tree_is_ready_for_activation_; +} + void SchedulerStateMachine::NotifyReadyToDraw() { active_tree_is_ready_to_draw_ = true; } diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h index 929d58550de..c2f3239f32e 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.h +++ b/chromium/cc/scheduler/scheduler_state_machine.h @@ -136,6 +136,7 @@ class CC_EXPORT SchedulerStateMachine { NONE, SEND_BEGIN_MAIN_FRAME, COMMIT, + POST_COMMIT, ACTIVATE_SYNC_TREE, PERFORM_IMPL_SIDE_INVALIDATION, DRAW_IF_POSSIBLE, @@ -158,6 +159,8 @@ class CC_EXPORT SchedulerStateMachine { void WillNotifyBeginMainFrameNotExpectedUntil(); void WillNotifyBeginMainFrameNotExpectedSoon(); void WillCommit(bool commit_had_no_updates); + void DidCommit(); + void DidPostCommit(); void WillActivate(); void WillDraw(); void WillBeginLayerTreeFrameSinkCreation(); @@ -287,6 +290,7 @@ class CC_EXPORT SchedulerStateMachine { // the notification received updated the state for the current pending tree, // if any. bool NotifyReadyToActivate(); + bool IsReadyToActivate(); // Indicates the active tree's visible tiles are ready to be drawn. void NotifyReadyToDraw(); @@ -354,6 +358,12 @@ class CC_EXPORT SchedulerStateMachine { return aborted_begin_main_frame_count_; } + bool pending_tree_is_ready_for_activation() const { + return pending_tree_is_ready_for_activation_; + } + + bool resourceless_draw() const { return resourceless_draw_; } + protected: bool BeginFrameRequiredForAction() const; bool BeginFrameNeededForVideo() const; @@ -380,6 +390,7 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldActivateSyncTree() const; bool ShouldSendBeginMainFrame() const; bool ShouldCommit() const; + bool ShouldRunPostCommit() const; bool ShouldPrepareTiles() const; bool ShouldInvalidateLayerTreeFrameSink() const; bool ShouldNotifyBeginMainFrameNotExpectedUntil() const; @@ -440,6 +451,7 @@ class CC_EXPORT SchedulerStateMachine { bool needs_prepare_tiles_ = false; bool needs_begin_main_frame_ = false; bool needs_one_begin_impl_frame_ = false; + bool needs_post_commit_ = false; bool visible_ = false; bool begin_frame_source_paused_ = false; bool resourceless_draw_ = false; diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index f331078d623..3cfc032b8c3 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -55,7 +55,7 @@ SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION); \ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); \ state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit(); \ - state.SetCanDraw(true); + state.SetCanDraw(true) namespace cc { @@ -99,6 +99,8 @@ const char* ActionToString(SchedulerStateMachine::Action action) { return "Action::SEND_BEGIN_MAIN_FRAME"; case Action::COMMIT: return "Action::COMMIT"; + case Action::POST_COMMIT: + return "Action::POST_COMMIT"; case Action::ACTIVATE_SYNC_TREE: return "Action::ACTIVATE_SYNC_TREE"; case Action::DRAW_IF_POSSIBLE: @@ -260,9 +262,14 @@ void PerformAction(StateMachine* sm, SchedulerStateMachine::Action action) { case SchedulerStateMachine::Action::COMMIT: { bool commit_has_no_updates = false; sm->WillCommit(commit_has_no_updates); + sm->DidCommit(); return; } + case SchedulerStateMachine::Action::POST_COMMIT: + sm->DidPostCommit(); + return; + case SchedulerStateMachine::Action::DRAW_FORCED: case SchedulerStateMachine::Action::DRAW_IF_POSSIBLE: { sm->WillDraw(); @@ -343,6 +350,40 @@ TEST(SchedulerStateMachineTest, BeginFrameNeeded) { EXPECT_FALSE(state.BeginFrameNeeded()); } +TEST(SchedulerStateMachineTest, BeginMainFrameIsHighestPriorityAction) { + SchedulerSettings default_scheduler_settings; + default_scheduler_settings.main_frame_before_activation_enabled = true; + StateMachine state(default_scheduler_settings); + SET_UP_STATE(state); + state.SetNeedsBeginMainFrame(); + state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); + state.NotifyReadyToCommit(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); + state.NotifyReadyToActivate(); + EXPECT_ACTION(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); + + // Still need to active, but sending BMF takes priority. + state.SetNeedsBeginMainFrame(); + state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); + + state.NotifyReadyToCommit(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); + state.OnBeginImplFrameDeadline(); + EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE); + + // Still need to draw, but sending BMF takes priority. + state.SetNeedsBeginMainFrame(); + state.IssueNextBeginImplFrame(); + EXPECT_ACTION(SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); +} + TEST(SchedulerStateMachineTest, TestNextActionNotifyBeginMainFrameNotExpectedUntil) { SchedulerSettings default_scheduler_settings; @@ -500,7 +541,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { StateMachine state(scheduler_settings); state.SetBeginMainFrameState( SchedulerStateMachine::BeginMainFrameState::IDLE); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsRedraw(false); state.SetNeedsBeginMainFrame(); @@ -514,6 +555,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE); @@ -537,6 +579,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); @@ -552,7 +595,7 @@ TEST(SchedulerStateMachineTest, FailedDrawForAnimationCheckerboardSetsNeedsCommitAndRetriesDraw) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -589,7 +632,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -623,6 +666,7 @@ TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) { // Finish the commit and activation. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -646,7 +690,7 @@ TEST(SchedulerStateMachineTest, SchedulerSettings scheduler_settings; scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced = 1; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start a commit. state.SetNeedsBeginMainFrame(); @@ -671,6 +715,7 @@ TEST(SchedulerStateMachineTest, // continue the commit as usual. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); EXPECT_TRUE(state.RedrawPending()); @@ -700,7 +745,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced = draw_limit; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start a commit. state.SetNeedsBeginMainFrame(); @@ -759,7 +804,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start a draw. state.SetNeedsRedraw(true); @@ -795,7 +840,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) { TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsRedraw(true); // Draw the first frame. @@ -976,12 +1021,13 @@ TEST(SchedulerStateMachineTest, state.SetNeedsRedraw(true); state.SetCanDraw(false); state.IssueNextBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); state.OnBeginImplFrameDeadline(); @@ -992,7 +1038,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) { SchedulerSettings scheduler_settings; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsBeginMainFrame(); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -1034,6 +1080,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) { // Finish the commit and activate, then make sure we start the next commit // immediately and draw on the next BeginImplFrame. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE( @@ -1052,7 +1099,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) { TEST(SchedulerStateMachineTest, TestFullCycle) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1072,6 +1119,7 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { // Commit. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // Activate. state.NotifyReadyToActivate(); @@ -1097,7 +1145,7 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1108,6 +1156,7 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1120,6 +1169,7 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); } TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) { @@ -1127,7 +1177,7 @@ TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) { scheduler_settings.commit_to_active_tree = true; scheduler_settings.main_frame_before_activation_enabled = false; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1138,6 +1188,7 @@ TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1163,6 +1214,7 @@ TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); EXPECT_TRUE(state.has_pending_tree()); state.OnBeginImplFrameDeadline(); @@ -1197,6 +1249,7 @@ TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_FALSE(state.has_pending_tree()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); EXPECT_TRUE(state.has_pending_tree()); } @@ -1206,7 +1259,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { scheduler_settings.commit_to_active_tree = true; scheduler_settings.main_frame_before_activation_enabled = false; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1226,6 +1279,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT); // Commit. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // Commit always calls NotifyReadyToActivate in this mode. state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1263,6 +1317,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); @@ -1284,7 +1339,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1308,6 +1363,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { // First commit and activate. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.active_tree_needs_first_draw()); @@ -1385,7 +1441,7 @@ TEST(SchedulerStateMachineTest, TestNoRequestLayerTreeFrameSinkWhenInvisible) { TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -1508,7 +1564,7 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) { TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); EXPECT_NE(SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION, state.NextAction()); @@ -1534,7 +1590,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenIdleAndCommitRequestedWhileRecreating) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); EXPECT_NE(SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION, state.NextAction()); @@ -1584,6 +1640,7 @@ TEST(SchedulerStateMachineTest, // Finish the commit, which should make the surface active. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_EQ(state.layer_tree_frame_sink_state(), SchedulerStateMachine::LayerTreeFrameSinkState:: WAITING_FOR_FIRST_ACTIVATION); @@ -1633,6 +1690,7 @@ TEST(SchedulerStateMachineTest, // Activate so we need the first draw state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); @@ -1650,7 +1708,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) { SchedulerSettings scheduler_settings; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Get a commit in flight. state.SetNeedsBeginMainFrame(); @@ -1679,6 +1737,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) { // Finish the frame, commit and activate. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1708,7 +1767,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgressAndAnotherCommitRequested) { SchedulerSettings scheduler_settings; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Get a commit in flight. state.SetNeedsBeginMainFrame(); @@ -1737,6 +1796,7 @@ TEST(SchedulerStateMachineTest, // Finish the frame, and commit and activate. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.active_tree_needs_first_draw()); @@ -1771,6 +1831,7 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1786,7 +1847,7 @@ TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostLayerTreeFrameSink) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsRedraw(true); @@ -1806,7 +1867,7 @@ TEST(SchedulerStateMachineTest, TestShouldAbortCurrentFrameAfterLostLayerTreeFrameSink) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetBeginMainFrameState( SchedulerStateMachine::BeginMainFrameState::SENT); @@ -1816,6 +1877,7 @@ TEST(SchedulerStateMachineTest, state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_TRUE(state.ShouldAbortCurrentFrame()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -1882,6 +1944,7 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) { // because we are not visible. state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.active_tree_needs_first_draw()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT); @@ -1907,6 +1970,7 @@ TEST(SchedulerStateMachineTest, state.NotifyReadyToCommit(); EXPECT_TRUE(state.ShouldAbortCurrentFrame()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.active_tree_needs_first_draw()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT); @@ -1916,7 +1980,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsBeginMainFrame(); state.DidLoseLayerTreeFrameSink(); @@ -1941,7 +2005,7 @@ TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) { TEST(SchedulerStateMachineTest, ReportIfNotDrawing) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); state.SetCanDraw(false); @@ -1968,7 +2032,7 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawing) { TEST(SchedulerStateMachineTest, ForceDrawForResourcelessSoftwareDraw) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetResourcelessSoftwareDraw(true); EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); @@ -2018,7 +2082,7 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyAfterAbortedCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // This test mirrors what happens during the first frame of a scroll gesture. // First we get the input event and a BeginFrame. @@ -2050,6 +2114,7 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline( state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); @@ -2067,7 +2132,7 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline( TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // This test ensures that impl-draws are prioritized over main thread updates // in prefer impl latency mode. @@ -2121,7 +2186,7 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyOnLostLayerTreeFrameSink) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsBeginMainFrame(); @@ -2141,7 +2206,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenInvisible) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsBeginMainFrame(); @@ -2161,7 +2226,7 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenBeginFrameSourcePaused) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetNeedsBeginMainFrame(); @@ -2180,7 +2245,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, TestDeferBeginMainFrame) { SchedulerSettings settings; StateMachine state(settings); - SET_UP_STATE(state) + SET_UP_STATE(state); state.SetDeferBeginMainFrame(true); @@ -2322,6 +2387,7 @@ TEST(SchedulerStateMachineTest, SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); state.OnBeginImplFrameDeadline(); @@ -2385,7 +2451,7 @@ TEST(SchedulerStateMachineTest, TEST(SchedulerStateMachineTest, NoImplSideInvalidationUntilFrameSinkActive) { SchedulerSettings settings; StateMachine state(settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Prefer impl side invalidation over begin main frame. state.set_should_defer_invalidation_for_fast_main_frame(false); @@ -2410,6 +2476,7 @@ TEST(SchedulerStateMachineTest, NoImplSideInvalidationUntilFrameSinkActive) { state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.OnBeginImplFrameDeadline(); state.OnBeginImplFrameIdle(); @@ -2452,6 +2519,7 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationWhenPendingTreeExists) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // Request an impl-side invalidation after the commit. The request should wait // till the current pending tree is activated. @@ -2497,6 +2565,7 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationWhileReadyToCommit) { state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); EXPECT_TRUE(state.needs_impl_side_invalidation()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_FALSE(state.needs_impl_side_invalidation()); } @@ -2547,6 +2616,7 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationsThrottledOnDraw) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); state.NotifyReadyToDraw(); @@ -2595,7 +2665,7 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) { SchedulerSettings scheduler_settings; scheduler_settings.wait_for_all_pipeline_stages_before_draw = true; StateMachine state(scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Start clean and set commit. state.SetNeedsBeginMainFrame(); @@ -2634,6 +2704,7 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) { state.CurrentBeginImplFrameDeadlineMode()); // Commit. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // We are blocking on activation. EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED, state.CurrentBeginImplFrameDeadlineMode()); @@ -2728,7 +2799,7 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) { TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) { SchedulerSettings settings; StateMachine state(settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Impl-side invalidation creates a pending tree which is activated but not // drawn in this frame. @@ -2751,6 +2822,7 @@ TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // We should be able to activate this tree without drawing the active tree. state.NotifyReadyToActivate(); @@ -2760,7 +2832,7 @@ TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) { TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // This test verifies that having pending mutations from Animation Worklets on // the active tree will not trigger the deadline early. @@ -2771,6 +2843,7 @@ TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); @@ -2826,7 +2899,7 @@ TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) { TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) { SchedulerSettings settings; StateMachine state(settings); - SET_UP_STATE(state) + SET_UP_STATE(state); // Verify that pending mutations from Animation Worklets block activation. state.SetNeedsBeginMainFrame(); @@ -2836,6 +2909,7 @@ TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); state.NotifyAnimationWorkletStateChange( SchedulerStateMachine::AnimationWorkletState::PROCESSING, SchedulerStateMachine::TreeType::PENDING); @@ -2859,6 +2933,7 @@ TEST(SchedulerStateMachineTest, BlockActivationIfPaintWorkletsPending) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); // Post-commit, we start working on PaintWorklets. It is not valid to activate @@ -2887,6 +2962,7 @@ TEST(SchedulerStateMachineTest, SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); // Even if we are aborting the frame, we must paint the pending tree before we @@ -2918,6 +2994,7 @@ TEST(SchedulerStateMachineTest, TestFullPipelineModeDoesntBlockAfterCommit) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); state.NotifyReadyToActivate(); @@ -2939,6 +3016,7 @@ TEST(SchedulerStateMachineTest, TestFullPipelineModeDoesntBlockAfterCommit) { SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT); // ... and make sure we're in a state where we can proceed, // rather than draw being blocked by the pending tree. state.OnBeginImplFrameDeadline(); diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index 3e404b232f2..498884d549d 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -201,7 +201,11 @@ class FakeSchedulerClient : public SchedulerClient, EXPECT_FALSE(inside_action_); base::AutoReset<bool> mark_inside(&inside_action_, true); PushAction("ScheduledActionCommit"); - scheduler_->DidCommit(); + } + void ScheduledActionPostCommit() override { + EXPECT_FALSE(inside_action_); + base::AutoReset<bool> mark_inside(&inside_action_, true); + PushAction("ScheduledActionPostCommit"); } void ScheduledActionActivateSyncTree() override { EXPECT_FALSE(inside_action_); @@ -680,7 +684,7 @@ TEST_F(SchedulerTest, RequestCommit) { // NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -795,7 +799,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { // Finish the first commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -824,7 +828,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { // to trigger the deadline early. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -1397,7 +1401,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -1435,7 +1439,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -1470,6 +1474,7 @@ void SchedulerTest::AdvanceAndMissOneFrame() { scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", "ScheduledActionCommit", + "ScheduledActionPostCommit", "ScheduledActionActivateSyncTree"); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); client_->Reset(); @@ -1713,7 +1718,8 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); - EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree"); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->SetCanDraw(false); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); @@ -1758,7 +1764,8 @@ TEST_F(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); - EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree"); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); // Clear the timing history. Make sure we don't skip the main frame until we @@ -1788,7 +1795,8 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() { scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); - EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree", + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); // Verify impl thread consistently operates in high latency mode @@ -1814,6 +1822,7 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() { // Verify that we don't skip the actions of the BeginImplFrame EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame", "ScheduledActionCommit", + "ScheduledActionPostCommit", "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); } @@ -1885,7 +1894,7 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) { // NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); // NotifyReadyToActivate should trigger the activation. @@ -1939,7 +1948,7 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled( // NotifyReadyToCommit should trigger the pending commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); // NotifyReadyToActivate should trigger the activation and draw. @@ -2045,7 +2054,8 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterBeginFrameStarted) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree"); client_->Reset(); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); @@ -2090,7 +2100,8 @@ TEST_F(SchedulerTest, client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree", + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionBeginLayerTreeFrameSinkCreation"); } @@ -2109,7 +2120,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->DidLoseLayerTreeFrameSink(); @@ -2165,7 +2176,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(scheduler_->begin_frames_expected()); // NotifyReadyToActivate should trigger the activation. @@ -2201,7 +2212,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -2233,7 +2244,7 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2259,7 +2270,7 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -2446,7 +2457,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -2540,7 +2551,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) { scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", - "ScheduledActionCommit", "ScheduledActionActivateSyncTree", + "ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); client_->Reset(); @@ -2576,7 +2588,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) { scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", - "ScheduledActionCommit", "ScheduledActionActivateSyncTree", + "ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); client_->Reset(); @@ -2614,7 +2627,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoonOnlyOncePerFrame) { scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", - "ScheduledActionCommit", "ScheduledActionActivateSyncTree", + "ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); client_->Reset(); @@ -2655,7 +2669,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_AlreadyIdle) { scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", - "ScheduledActionCommit", "ScheduledActionActivateSyncTree", + "ScheduledActionCommit", "ScheduledActionPostCommit", + "ScheduledActionActivateSyncTree", "ScheduledActionDrawIfPossible"); client_->Reset(); @@ -3012,7 +3027,7 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) { client_->Reset(); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -3130,7 +3145,7 @@ TEST_F(SchedulerTest, SynchronousCompositorAllowsActivateBeforeDraw) { // Commit and activate. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("ScheduledActionActivateSyncTree"); @@ -3148,7 +3163,7 @@ TEST_F(SchedulerTest, SynchronousCompositorAllowsActivateBeforeDraw) { // Commit and activate. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("ScheduledActionActivateSyncTree"); @@ -3208,7 +3223,7 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) { scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); client_->Reset(); scheduler_->NotifyReadyToActivate(); @@ -3376,7 +3391,7 @@ TEST_F(SchedulerTest, ImplSideInvalidationsMergedWithCommit) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_FALSE(scheduler_->needs_impl_side_invalidation()); } @@ -3565,7 +3580,7 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) { // Allow the commit now. NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -3920,7 +3935,7 @@ TEST_F(SchedulerTest, client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); // Draw deadline. client_->Reset(); @@ -4182,7 +4197,7 @@ TEST_F(SchedulerTestForPowerMode, BeginMainFramePowerModeVoter) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); scheduler_->NotifyReadyToCommit(nullptr); - EXPECT_ACTIONS("ScheduledActionCommit"); + EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit"); EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kMainThreadAnimation); client_->Reset(); diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc index 3507754e0b8..f9c24c2c0c5 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache.cc @@ -466,6 +466,44 @@ sk_sp<SkImage> MakeTextureImage(viz::RasterContextProvider* context, return uploaded_image; } +// We use this below, instead of just a std::unique_ptr, so that we can run +// a Finch experiment to check the impact of not using discardable memory on the +// GPU decode path. +class HeapDiscardableMemory : public base::DiscardableMemory { + public: + explicit HeapDiscardableMemory(size_t size) + : memory_(new char[size]), size_(size) {} + ~HeapDiscardableMemory() override = default; + [[nodiscard]] bool Lock() override { + // Locking only succeeds when we have not yet discarded the memory (i.e. if + // we have never called |Unlock()|.) + return memory_ != nullptr; + } + void Unlock() override { Discard(); } + void* data() const override { + DCHECK(memory_); + return static_cast<void*>(memory_.get()); + } + void DiscardForTesting() override { Discard(); } + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override { + auto* dump = pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, size_); + return dump; + } + + private: + void Discard() { + memory_.reset(); + size_ = 0; + } + + std::unique_ptr<char[]> memory_; + size_t size_; +}; + } // namespace // Extract the information to uniquely identify a DrawImage for the purposes of @@ -953,6 +991,7 @@ GpuImageDecodeCache::GpuImageDecodeCache( max_working_set_bytes_(max_working_set_bytes), max_working_set_items_(kMaxItemsInWorkingSet), dark_mode_filter_(dark_mode_filter) { + DCHECK_NE(generator_client_id_, PaintImage::kDefaultGeneratorClientId); // Note that to compute |allow_accelerated_jpeg_decodes_| and // |allow_accelerated_webp_decodes_|, the last thing we check is the feature // flag. That's because we want to ensure that we're in OOP-R mode and the @@ -1986,10 +2025,17 @@ void GpuImageDecodeCache::DecodeImageIfNecessary( sk_sp<SkImage> image_v; { base::AutoUnlock unlock(lock_); - auto* allocator = base::DiscardableMemoryAllocator::GetInstance(); - backing_memory = allocator->AllocateLockedDiscardableMemoryWithRetryOrDie( - image_data->size, base::BindOnce(&GpuImageDecodeCache::ClearCache, - base::Unretained(this))); + if (base::FeatureList::IsEnabled( + features::kNoDiscardableMemoryForGpuDecodePath)) { + backing_memory = + std::make_unique<HeapDiscardableMemory>(image_data->size); + } else { + auto* allocator = base::DiscardableMemoryAllocator::GetInstance(); + backing_memory = allocator->AllocateLockedDiscardableMemoryWithRetryOrDie( + image_data->size, base::BindOnce(&GpuImageDecodeCache::ClearCache, + base::Unretained(this))); + } + sk_sp<SkColorSpace> color_space = ColorSpaceForImageDecode(draw_image, image_data->mode); auto release_proc = [](const void*, void*) {}; @@ -2136,7 +2182,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, sk_sp<SkColorSpace> decoded_target_colorspace = ColorSpaceForImageDecode(draw_image, image_data->mode); if (target_color_space && decoded_target_colorspace) { - if (!gfx::ColorSpace(*decoded_target_colorspace).IsPQOrHLG() && + if (!gfx::ColorSpace(*decoded_target_colorspace).IsToneMappedByDefault() && SkColorSpace::Equals(target_color_space.get(), decoded_target_colorspace.get())) { target_color_space = nullptr; @@ -2157,7 +2203,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, } else if (image_data->yuva_pixmap_info.has_value()) { const bool needs_tone_mapping = decoded_target_colorspace && - gfx::ColorSpace(*decoded_target_colorspace).IsPQOrHLG(); + gfx::ColorSpace(*decoded_target_colorspace).IsToneMappedByDefault(); UploadImageIfNecessary_TransferCache_SoftwareDecode_YUVA( draw_image, image_data, decoded_target_colorspace, needs_tone_mapping ? target_color_params : absl::nullopt); @@ -2861,8 +2907,17 @@ 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_params == draw_image.target_color_params(); + sk_sp<SkColorSpace> decoded_target_colorspace = + ColorSpaceForImageDecode(draw_image, image_data->mode); + bool color_is_compatible = false; + if (!decoded_target_colorspace || + !gfx::ColorSpace(*decoded_target_colorspace).IsToneMappedByDefault()) { + color_is_compatible = image_data->target_color_params.color_space == + draw_image.target_color_space(); + } else { + color_is_compatible = + image_data->target_color_params == draw_image.target_color_params(); + } if (!color_is_compatible) return false; if (is_scaled && (!scale_is_compatible || !quality_is_compatible)) diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc index 6230a6b7cd6..0e8bba94795 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc @@ -55,7 +55,7 @@ class GpuImageDecodeCachePerfTest ASSERT_EQ(result, gpu::ContextResult::kSuccess); cache_ = std::make_unique<GpuImageDecodeCache>( context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType, - kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId, + kCacheSize, MaxTextureSize(), PaintImage::GetNextGeneratorClientId(), nullptr); } diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc index a2b72d799c4..b72b54d5569 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc @@ -12,6 +12,7 @@ #include <tuple> #include <vector> +#include "base/command_line.h" #include "base/feature_list.h" #include "base/memory/raw_ptr.h" #include "base/test/scoped_feature_list.h" @@ -380,7 +381,8 @@ class GpuImageDecodeCacheTest bool /* allow_accelerated_jpeg_decoding */, bool /* allow_accelerated_webp_decoding */, bool /* advertise_accelerated_decoding */, - bool /* enable_clipped_image_scaling */>> { + bool /* enable_clipped_image_scaling */, + bool /* no_discardable_memory */>> { public: void SetUp() override { std::vector<base::Feature> enabled_features; @@ -390,6 +392,10 @@ class GpuImageDecodeCacheTest allow_accelerated_webp_decoding_ = std::get<4>(GetParam()); if (allow_accelerated_webp_decoding_) enabled_features.push_back(features::kVaapiWebPImageDecodeAcceleration); + no_discardable_memory_ = std::get<7>(GetParam()); + if (no_discardable_memory_) + enabled_features.push_back( + features::kNoDiscardableMemoryForGpuDecodePath); feature_list_.InitWithFeatures(enabled_features, {} /* disabled_features */); advertise_accelerated_decoding_ = std::get<5>(GetParam()); @@ -423,7 +429,7 @@ class GpuImageDecodeCacheTest return std::make_unique<GpuImageDecodeCache>( context_provider_.get(), use_transfer_cache_, color_type_, memory_limit_bytes, max_texture_size_, - PaintImage::kDefaultGeneratorClientId, dark_mode_filter); + PaintImage::GetNextGeneratorClientId(), dark_mode_filter); } // Returns dimensions for an image that will not fit in GPU memory and hence @@ -691,6 +697,7 @@ class GpuImageDecodeCacheTest bool allow_accelerated_webp_decoding_; bool advertise_accelerated_decoding_; bool enable_clipped_image_scaling_; + bool no_discardable_memory_; int max_texture_size_ = 0; }; @@ -3131,7 +3138,7 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) { // If `draw_image` is tone mapped, then it will be converted to RGBA // during tone mapping. bool color_converted_to_rgba = use_transfer_cache_ && - decoded_cs.IsPQOrHLG() && + decoded_cs.IsToneMappedByDefault() && cache->SupportsColorSpaceConversion(); if (decodes_to_yuv && !color_converted_to_rgba) { @@ -3628,7 +3635,8 @@ INSTANTIATE_TEST_SUITE_P( testing::Values(false) /* allow_accelerated_jpeg_decoding */, testing::Values(false) /* allow_accelerated_webp_decoding */, testing::Values(false) /* advertise_accelerated_decoding */, - testing::Bool() /* enable_clipped_image_scaling */)); + testing::Bool() /* enable_clipped_image_scaling */, + testing::Values(false) /* no_discardable_memory */)); INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsOOPR, @@ -3640,7 +3648,8 @@ INSTANTIATE_TEST_SUITE_P( testing::Values(false) /* allow_accelerated_jpeg_decoding */, testing::Values(false) /* allow_accelerated_webp_decoding */, testing::Values(false) /* advertise_accelerated_decoding */, - testing::Values(false) /* enable_clipped_image_scaling */)); + testing::Values(false) /* enable_clipped_image_scaling */, + testing::Values(false) /* no_discardable_memory */)); class GpuImageDecodeCacheWithAcceleratedDecodesTest : public GpuImageDecodeCacheTest { @@ -3956,7 +3965,8 @@ INSTANTIATE_TEST_SUITE_P( testing::Values(true) /* allow_accelerated_jpeg_decoding */, testing::Values(true) /* allow_accelerated_webp_decoding */, testing::Values(true) /* advertise_accelerated_decoding */, - testing::Values(false) /* enable_clipped_image_scaling */)); + testing::Values(false) /* enable_clipped_image_scaling */, + testing::Bool() /* no_discardable_memory */)); class GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest : public GpuImageDecodeCacheWithAcceleratedDecodesTest {}; @@ -4092,14 +4102,14 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsOOPR, GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, - testing::Combine( - testing::Values(kN32_SkColorType), - testing::Values(true) /* use_transfer_cache */, - testing::Bool() /* do_yuv_decode */, - testing::Bool() /* allow_accelerated_jpeg_decoding */, - testing::Bool() /* allow_accelerated_webp_decoding */, - testing::Bool() /* advertise_accelerated_decoding */, - testing::Values(false) /* enable_clipped_image_scaling */)); + testing::Combine(testing::Values(kN32_SkColorType), + testing::Values(true) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::Bool() /* allow_accelerated_jpeg_decoding */, + testing::Bool() /* allow_accelerated_webp_decoding */, + testing::Bool() /* advertise_accelerated_decoding */, + testing::Values(false) /* enable_clipped_image_scaling */, + testing::Bool() /* no_discardable_memory */)); #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE diff --git a/chromium/cc/tiles/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h index c27c0316bfa..4198f11350c 100644 --- a/chromium/cc/tiles/picture_layer_tiling.h +++ b/chromium/cc/tiles/picture_layer_tiling.h @@ -288,7 +288,7 @@ class CC_EXPORT PictureLayerTiling { // `tiling_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - const PictureLayerTiling* tiling_ = nullptr; + RAW_PTR_EXCLUSION const PictureLayerTiling* tiling_ = nullptr; gfx::Size coverage_rect_max_bounds_; gfx::Rect coverage_rect_; @@ -296,7 +296,7 @@ class CC_EXPORT PictureLayerTiling { // `current_tile_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - Tile* current_tile_ = nullptr; + RAW_PTR_EXCLUSION Tile* current_tile_ = nullptr; gfx::Rect current_geometry_rect_; int tile_i_ = 0; diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc index b709fab69f3..28b6a196983 100644 --- a/chromium/cc/tiles/software_image_decode_cache.cc +++ b/chromium/cc/tiles/software_image_decode_cache.cc @@ -149,6 +149,7 @@ SoftwareImageDecodeCache::SoftwareImageDecodeCache( color_type_(color_type), generator_client_id_(generator_client_id), max_items_in_cache_(kNormalMaxItemsInCacheForSoftware) { + DCHECK_NE(generator_client_id_, PaintImage::kDefaultGeneratorClientId); // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). // Don't register a dump provider in these cases. if (base::ThreadTaskRunnerHandle::IsSet()) { diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc index 52beb179d2a..90abb8dc920 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc @@ -29,7 +29,7 @@ class TestSoftwareImageDecodeCache : public SoftwareImageDecodeCache { TestSoftwareImageDecodeCache() : SoftwareImageDecodeCache(kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId) {} + PaintImage::GetNextGeneratorClientId()) {} }; SkM44 CreateMatrix(const SkSize& scale, bool is_decomposable) { 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 4fc04c1751b..0a89147856e 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc @@ -83,7 +83,7 @@ class N32Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); } }; @@ -92,7 +92,7 @@ class RGBA4444Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kARGB_4444_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); } }; @@ -101,7 +101,7 @@ class RGBA_F16Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kRGBA_F16_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::GetNextGeneratorClientId()); } }; diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc index 3afc048dbe2..a8cb3fd52e5 100644 --- a/chromium/cc/tiles/tile.cc +++ b/chromium/cc/tiles/tile.cc @@ -25,7 +25,7 @@ Tile::Tile(TileManager* tile_manager, int source_frame_number, int flags) : tile_manager_(tile_manager), - tiling_(info.tiling), + tiling_(info.tiling.get()), content_rect_(info.content_rect), enclosing_layer_rect_(info.enclosing_layer_rect), raster_transform_(info.raster_transform), diff --git a/chromium/cc/tiles/tile.h b/chromium/cc/tiles/tile.h index bf4d2d6eff6..cde7850f9e4 100644 --- a/chromium/cc/tiles/tile.h +++ b/chromium/cc/tiles/tile.h @@ -29,7 +29,7 @@ class TileManager; class CC_EXPORT Tile { public: struct CreateInfo { - const PictureLayerTiling* tiling = nullptr; + raw_ptr<const PictureLayerTiling> tiling = nullptr; int tiling_i_index = 0; int tiling_j_index = 0; gfx::Rect enclosing_layer_rect; diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index caf59cac516..000c0c5a02d 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -748,12 +748,12 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { // We analyze for solid color here, to decide to continue // or drop the tile for scheduling and raster. tile->set_solid_color_analysis_performed(true); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; bool is_solid_color = prioritized_tile.raster_source()->PerformSolidColorAnalysis( tile->enclosing_layer_rect(), &color); if (is_solid_color) { - tile->draw_info().set_solid_color(color); + tile->draw_info().set_solid_color(color.toSkColor()); client_->NotifyTileStateChanged(tile); continue; } diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index b18e59c4a11..3086adbf21e 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -1915,7 +1915,7 @@ TEST_F(PixelInspectTileManagerTest, LowResHasNoImage) { std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(size); - recording_source->SetBackgroundColor(SK_ColorTRANSPARENT); + recording_source->SetBackgroundColor(SkColors::kTransparent); recording_source->SetRequiresClear(true); PaintFlags flags; flags.setColor(SK_ColorGREEN); @@ -3569,7 +3569,7 @@ TEST_F(DecodedImageTrackerTileManagerTest, DecodedImageTrackerDropsLocksOnUse) { class HdrImageTileManagerTest : public CheckerImagingTileManagerTest { public: - void DecodeHdrImage(const gfx::ColorSpace& raster_cs) { + void DecodeHdrImage(const gfx::ColorSpace& output_cs) { auto color_space = gfx::ColorSpace::CreateHDR10(); auto size = gfx::Size(250, 250); auto info = @@ -3586,7 +3586,7 @@ class HdrImageTileManagerTest : public CheckerImagingTileManagerTest { // Add the image to our decoded_image_tracker. TargetColorParams target_color_params; - target_color_params.color_space = raster_cs; + target_color_params.color_space = output_cs; host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode( hdr_image, target_color_params, base::DoNothing()); FlushDecodeTasks(); @@ -3606,8 +3606,8 @@ class HdrImageTileManagerTest : public CheckerImagingTileManagerTest { SetupPendingTree(raster_source, kTileSize, invalidation); constexpr float kCustomWhiteLevel = 200.f; - auto display_cs = gfx::DisplayColorSpaces(raster_cs); - if (raster_cs.IsHDR()) + auto display_cs = gfx::DisplayColorSpaces(output_cs); + if (output_cs.IsHDR()) display_cs.SetSDRMaxLuminanceNits(kCustomWhiteLevel); pending_layer()->layer_tree_impl()->SetDisplayColorSpaces(display_cs); @@ -3628,7 +3628,8 @@ class HdrImageTileManagerTest : public CheckerImagingTileManagerTest { auto pending_tiles = pending_tiling->AllTilesForTesting(); ASSERT_FALSE(pending_tiles.empty()); - if (raster_cs.IsHDR()) { + const auto raster_cs = gfx::ColorSpace::CreateExtendedSRGB(); + if (output_cs.IsHDR()) { // Only the last tile will have any pending tasks. const auto& pending_tasks = host_impl()->tile_manager()->decode_tasks_for_testing( @@ -3647,7 +3648,7 @@ class HdrImageTileManagerTest : public CheckerImagingTileManagerTest { ASSERT_FALSE( host_impl()->tile_manager()->HasScheduledTileTasksForTesting()); - auto expected_format = raster_cs.IsHDR() ? viz::RGBA_F16 : viz::RGBA_8888; + auto expected_format = output_cs.IsHDR() ? viz::RGBA_F16 : viz::RGBA_8888; auto all_tiles = host_impl()->tile_manager()->AllTilesForTesting(); for (const auto* tile : all_tiles) EXPECT_EQ(expected_format, tile->draw_info().resource_format()); diff --git a/chromium/cc/tiles/tiling_set_eviction_queue.h b/chromium/cc/tiles/tiling_set_eviction_queue.h index 6b830f1a3c0..662fb19a742 100644 --- a/chromium/cc/tiles/tiling_set_eviction_queue.h +++ b/chromium/cc/tiles/tiling_set_eviction_queue.h @@ -9,6 +9,7 @@ #include <vector> +#include "base/memory/raw_ptr_exclusion.h" #include "cc/cc_export.h" #include "cc/tiles/picture_layer_tiling_set.h" #include "cc/tiles/prioritized_tile.h" @@ -115,7 +116,7 @@ class CC_EXPORT TilingSetEvictionQueue { // `tilings_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data and tab_search:top100:2020). - std::vector<PictureLayerTiling*>* tilings_; + RAW_PTR_EXCLUSION std::vector<PictureLayerTiling*>* tilings_; WhichTree tree_; PictureLayerTiling::PriorityRectType priority_rect_type_; diff --git a/chromium/cc/tiles/tiling_set_raster_queue_all.h b/chromium/cc/tiles/tiling_set_raster_queue_all.h index 57cebbf74e8..76a4f1969d5 100644 --- a/chromium/cc/tiles/tiling_set_raster_queue_all.h +++ b/chromium/cc/tiles/tiling_set_raster_queue_all.h @@ -8,6 +8,7 @@ #include <stddef.h> #include "base/containers/stack_container.h" +#include "base/memory/raw_ptr_exclusion.h" #include "base/notreached.h" #include "cc/cc_export.h" #include "cc/tiles/picture_layer_tiling_set.h" @@ -67,8 +68,8 @@ class CC_EXPORT TilingSetRasterQueueAll { // `tiling_` and `tiling_data_` are not a raw_ptr<...> for performance // reasons (based on analysis of sampling profiler data and // tab_search:top100:2020). - PictureLayerTiling* tiling_; - TilingData* tiling_data_; + RAW_PTR_EXCLUSION PictureLayerTiling* tiling_; + RAW_PTR_EXCLUSION TilingData* tiling_data_; PictureLayerTiling::PriorityRectType priority_rect_type_; gfx::Rect pending_visible_rect_; @@ -197,7 +198,7 @@ class CC_EXPORT TilingSetRasterQueueAll { // `tiling_set_` is not a raw_ptr<...> for performance reasons (based on // analysis of sampling profiler data). - PictureLayerTilingSet* tiling_set_; + RAW_PTR_EXCLUSION PictureLayerTilingSet* tiling_set_; struct IterationStage { IterationStage(IteratorType type, TilePriority::PriorityBin bin); diff --git a/chromium/cc/tiles/tiling_set_raster_queue_required.h b/chromium/cc/tiles/tiling_set_raster_queue_required.h index 1a89cad01f7..64f9dc2735e 100644 --- a/chromium/cc/tiles/tiling_set_raster_queue_required.h +++ b/chromium/cc/tiles/tiling_set_raster_queue_required.h @@ -5,6 +5,7 @@ #ifndef CC_TILES_TILING_SET_RASTER_QUEUE_REQUIRED_H_ #define CC_TILES_TILING_SET_RASTER_QUEUE_REQUIRED_H_ +#include "base/memory/raw_ptr_exclusion.h" #include "cc/cc_export.h" #include "cc/tiles/picture_layer_tiling_set.h" #include "cc/tiles/raster_tile_priority_queue.h" @@ -45,8 +46,8 @@ class CC_EXPORT TilingSetRasterQueueRequired { // `tiling_` and `tiling_data_` are not a raw_ptr<...> for performance // reasons (based on analysis of sampling profiler data and // tab_search:top100:2020). - PictureLayerTiling* tiling_; - TilingData* tiling_data_; + RAW_PTR_EXCLUSION PictureLayerTiling* tiling_; + RAW_PTR_EXCLUSION TilingData* tiling_data_; PrioritizedTile current_tile_; TilingData::Iterator visible_iterator_; diff --git a/chromium/cc/trees/browser_controls_params.h b/chromium/cc/trees/browser_controls_params.h index 91311103e78..9aab1b8a303 100644 --- a/chromium/cc/trees/browser_controls_params.h +++ b/chromium/cc/trees/browser_controls_params.h @@ -10,10 +10,6 @@ namespace cc { struct CC_EXPORT BrowserControlsParams { - BrowserControlsParams() = default; - BrowserControlsParams(const BrowserControlsParams& other) = default; - ~BrowserControlsParams() = default; - // The height of the top controls (always 0 on platforms where URL-bar hiding // isn't supported). float top_controls_height = 0.f; diff --git a/chromium/cc/trees/commit_state.cc b/chromium/cc/trees/commit_state.cc index e541fa5d25f..6abac8a47ea 100644 --- a/chromium/cc/trees/commit_state.cc +++ b/chromium/cc/trees/commit_state.cc @@ -38,7 +38,10 @@ CommitState::CommitState(const CommitState& prev) overscroll_behavior(prev.overscroll_behavior), background_color(prev.background_color), viewport_property_ids(prev.viewport_property_ids), - local_surface_id_from_parent(prev.local_surface_id_from_parent) { + local_surface_id_from_parent(prev.local_surface_id_from_parent), + previous_surfaces_visual_update_duration( + prev.previous_surfaces_visual_update_duration), + visual_update_duration(prev.visual_update_duration) { memcpy(event_listener_properties, prev.event_listener_properties, sizeof(event_listener_properties)); } diff --git a/chromium/cc/trees/commit_state.h b/chromium/cc/trees/commit_state.h index b4978d873b7..85f2ad29805 100644 --- a/chromium/cc/trees/commit_state.h +++ b/chromium/cc/trees/commit_state.h @@ -12,6 +12,7 @@ #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "cc/benchmarks/micro_benchmark_impl.h" #include "cc/cc_export.h" @@ -104,6 +105,8 @@ struct CC_EXPORT CommitState { SkColor background_color = SK_ColorWHITE; ViewportPropertyIds viewport_property_ids; viz::LocalSurfaceId local_surface_id_from_parent; + base::TimeDelta previous_surfaces_visual_update_duration; + base::TimeDelta visual_update_duration; // ------------------------------------------------------------------------- // Take/reset: these values are reset on the LayerTreeHost between commits. @@ -120,6 +123,7 @@ struct CC_EXPORT CommitState { bool new_local_surface_id_request = false; bool next_commit_forces_recalculate_raster_scales = false; bool next_commit_forces_redraw = false; + uint64_t trace_id = 0; EventMetrics::List event_metrics; // Latency information for work done in ProxyMain::BeginMainFrame. The // unique_ptr is allocated in RequestMainFrameUpdate, and passed to Blink's @@ -162,7 +166,7 @@ struct CC_EXPORT ThreadUnsafeCommitState { } LayerListConstIterator end() const { return LayerListConstIterator(nullptr); } - MutatorHost* mutator_host; + raw_ptr<MutatorHost> mutator_host; PropertyTrees property_trees; scoped_refptr<Layer> root_layer; }; diff --git a/chromium/cc/trees/draw_properties_unittest.cc b/chromium/cc/trees/draw_properties_unittest.cc index f18d813c165..6534341fdfa 100644 --- a/chromium/cc/trees/draw_properties_unittest.cc +++ b/chromium/cc/trees/draw_properties_unittest.cc @@ -1680,14 +1680,16 @@ TEST_F(DrawPropertiesTest, LargeTransforms) { static bool TransformIsAnimating(LayerImpl* layer) { MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->IsAnimatingTransformProperty( - layer->element_id(), layer->GetElementTypeForAnimation()); + return host->IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::TRANSFORM); } static bool HasPotentiallyRunningTransformAnimation(LayerImpl* layer) { MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->HasPotentiallyRunningTransformAnimation( - layer->element_id(), layer->GetElementTypeForAnimation()); + return host->HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::TRANSFORM); } TEST_F(DrawPropertiesTest, @@ -6648,6 +6650,7 @@ TEST_F(DrawPropertiesTest, LayerSkippingInSubtreeOfSingularTransform) { std::unique_ptr<KeyframeModel> transform_animation(KeyframeModel::Create( std::move(curve), 3, 3, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM))); + transform_animation->set_affects_pending_elements(false); scoped_refptr<Animation> animation(Animation::Create(1)); timeline_impl()->AttachAnimation(animation); animation->AddKeyframeModel(std::move(transform_animation)); diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc index 02a889cad64..b9d99c69cb4 100644 --- a/chromium/cc/trees/draw_property_utils.cc +++ b/chromium/cc/trees/draw_property_utils.cc @@ -28,6 +28,7 @@ #include "cc/trees/property_tree_builder.h" #include "cc/trees/scroll_node.h" #include "cc/trees/transform_node.h" +#include "cc/trees/viewport_property_ids.h" #include "components/viz/common/display/de_jelly.h" #include "components/viz/common/shared_element_resource_id.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -1425,7 +1426,8 @@ void FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl, } } -void ComputeTransforms(TransformTree* transform_tree) { +void ComputeTransforms(TransformTree* transform_tree, + const ViewportPropertyIds& viewport_property_ids) { if (!transform_tree->needs_update()) { #if DCHECK_IS_ON() // If the transform tree does not need an update, no TransformNode should @@ -1439,7 +1441,7 @@ void ComputeTransforms(TransformTree* transform_tree) { } for (int i = kContentsRootPropertyNodeId; i < static_cast<int>(transform_tree->size()); ++i) - transform_tree->UpdateTransforms(i); + transform_tree->UpdateTransforms(i, &viewport_property_ids); transform_tree->set_needs_update(false); } @@ -1460,14 +1462,16 @@ void UpdatePropertyTrees(LayerTreeHost* layer_tree_host) { property_trees->clip_tree_mutable().set_needs_update(true); property_trees->effect_tree_mutable().set_needs_update(true); } - ComputeTransforms(&property_trees->transform_tree_mutable()); + + ComputeTransforms(&property_trees->transform_tree_mutable(), + layer_tree_host->viewport_property_ids()); ComputeEffects(&property_trees->effect_tree_mutable()); // Computation of clips uses ToScreen which is updated while computing // transforms. So, ComputeTransforms should be before ComputeClips. ComputeClips(property_trees); } -void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer, +void UpdatePropertyTreesAndRenderSurfaces(LayerTreeImpl* layer_tree_impl, PropertyTrees* property_trees) { if (property_trees->transform_tree().needs_update()) { property_trees->clip_tree_mutable().set_needs_update(true); @@ -1475,7 +1479,8 @@ void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer, } UpdateRenderTarget(&property_trees->effect_tree_mutable()); - ComputeTransforms(&property_trees->transform_tree_mutable()); + ComputeTransforms(&property_trees->transform_tree_mutable(), + layer_tree_impl->viewport_property_ids()); ComputeEffects(&property_trees->effect_tree_mutable()); // Computation of clips uses ToScreen which is updated while computing // transforms. So, ComputeTransforms should be before ComputeClips. @@ -1555,8 +1560,7 @@ void CalculateDrawProperties( gfx::RectF(layer_tree_impl->GetDeviceViewport())); property_trees->transform_tree_mutable().SetRootScaleAndTransform( layer_tree_impl->device_scale_factor(), layer_tree_impl->DrawTransform()); - UpdatePropertyTreesAndRenderSurfaces(layer_tree_impl->root_layer(), - property_trees); + UpdatePropertyTreesAndRenderSurfaces(layer_tree_impl, property_trees); { TRACE_EVENT0("cc", "draw_property_utils::FindLayersThatNeedUpdates"); diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h index b80b38e3ab9..2c6d94c42a2 100644 --- a/chromium/cc/trees/draw_property_utils.h +++ b/chromium/cc/trees/draw_property_utils.h @@ -24,6 +24,7 @@ class TransformTree; class PropertyTrees; struct EffectNode; struct TransformNode; +struct ViewportPropertyIds; namespace draw_property_utils { @@ -32,7 +33,9 @@ void CC_EXPORT ConcatInverseSurfaceContentsScale(const EffectNode* effect_node, // Computes combined (screen space) transforms for every node in the transform // tree. This must be done prior to calling |ComputeClips|. -void CC_EXPORT ComputeTransforms(TransformTree* transform_tree); +void CC_EXPORT +ComputeTransforms(TransformTree* transform_tree, + const ViewportPropertyIds& viewport_property_ids); // Computes screen space opacity for every node in the opacity tree. void CC_EXPORT ComputeEffects(EffectTree* effect_tree); @@ -40,7 +43,7 @@ void CC_EXPORT ComputeEffects(EffectTree* effect_tree); void CC_EXPORT UpdatePropertyTrees(LayerTreeHost* layer_tree_host); void CC_EXPORT -UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer, +UpdatePropertyTreesAndRenderSurfaces(LayerTreeImpl* layer_tree_impl, PropertyTrees* property_trees); void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host, diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc index b08f9cf0e5e..ffaddbaecc2 100644 --- a/chromium/cc/trees/effect_node.cc +++ b/chromium/cc/trees/effect_node.cc @@ -182,7 +182,7 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const { value); if (mask_filter_info.HasRoundedCorners()) { MathUtil::AddCornerRadiiToTracedValue( - "mask_filter_rounded_corner_raii", + "mask_filter_rounded_corners_radii", mask_filter_info.rounded_corner_bounds(), value); value->SetBoolean("mask_filter_is_fast_rounded_corner", is_fast_rounded_corner); diff --git a/chromium/cc/trees/layer_tree_frame_sink.h b/chromium/cc/trees/layer_tree_frame_sink.h index e68f245b08e..2aa0f851421 100644 --- a/chromium/cc/trees/layer_tree_frame_sink.h +++ b/chromium/cc/trees/layer_tree_frame_sink.h @@ -21,7 +21,6 @@ #include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/gpu/raster_context_provider.h" #include "components/viz/common/resources/returned_resource.h" -#include "gpu/command_buffer/common/texture_in_use_response.h" #include "ui/gfx/color_space.h" namespace gpu { diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h index 82dcc904980..6855ae2576f 100644 --- a/chromium/cc/trees/layer_tree_frame_sink_client.h +++ b/chromium/cc/trees/layer_tree_frame_sink_client.h @@ -11,7 +11,6 @@ #include "base/memory/ref_counted.h" #include "cc/cc_export.h" #include "components/viz/common/resources/returned_resource.h" -#include "gpu/command_buffer/common/texture_in_use_response.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index 730f3952679..9636bffb09f 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -409,6 +409,8 @@ std::unique_ptr<CommitState> LayerTreeHost::WillCommit( client_->WillCommit(has_updates ? *result : *pending_commit_state()); pending_commit_state()->source_frame_number++; commit_completion_event_ = std::move(completion); + pending_commit_state()->previous_surfaces_visual_update_duration = + base::TimeDelta(); return result; } @@ -732,7 +734,7 @@ void LayerTreeHost::SetDebugState(const LayerTreeDebugState& new_debug_state) { void LayerTreeHost::ApplyPageScaleDeltaFromImplSide(float page_scale_delta) { DCHECK(IsMainThread()); - DCHECK(CommitRequested()); + DCHECK(syncing_deltas_for_test_ || CommitRequested()); if (page_scale_delta == 1.f) return; float page_scale = @@ -1011,6 +1013,21 @@ void LayerTreeHost::UpdateScrollOffsetFromImpl( transform_node->needs_local_transform_update = true; transform_node->transform_changed = true; transform_tree.set_needs_update(true); + + // If the scroll was realized on the compositor, then its transform node + // is already updated (see LayerTreeImpl::DidUpdateScrollOffset) and we + // are now "catching up" to it on main, so we don't need a commit. + // + // But if the scroll was NOT realized on the compositor, we need a + // commit to push the transform change. + // + // Skip this if scroll unification is disabled as we will not set + // ScrollNode::is_composited in that case. + // + if (base::FeatureList::IsEnabled(features::kScrollUnification) && + !scroll_tree.CanRealizeScrollsOnCompositor(*scroll_node)) { + SetNeedsCommit(); + } } // The transform tree has been modified which requires a call to @@ -1089,6 +1106,11 @@ void LayerTreeHost::NotifyThroughputTrackerResults( client_->NotifyThroughputTrackerResults(std::move(results)); } +void LayerTreeHost::ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) { + client_->ReportEventLatency(std::move(latencies)); +} + const base::WeakPtr<CompositorDelegateForInput>& LayerTreeHost::GetDelegateForInput() const { DCHECK(IsMainThread()); @@ -1378,7 +1400,7 @@ void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor, // We should never process non-unit page_scale_delta for an OOPIF subframe. // TODO(wjmaclean): Remove this dcheck as a pre-condition to closing the bug. // https://crbug.com/845097 - DCHECK(!settings_.is_layer_tree_for_subframe || + DCHECK(settings_.is_for_scalable_page || page_scale_factor == pending_commit_state()->page_scale_factor) << "Setting PSF in oopif subframe: old psf = " << pending_commit_state()->page_scale_factor @@ -1505,6 +1527,13 @@ void LayerTreeHost::SetLocalSurfaceIdFromParent( pending_commit_state()->local_surface_id_from_parent = local_surface_id_from_parent; + // When we are switching to a new viz::LocalSurfaceId add our current visual + // update duration to that of previous surfaces, and clear out the total. So + // that we can begin to track the updates for this new Surface. + pending_commit_state()->previous_surfaces_visual_update_duration += + pending_commit_state()->visual_update_duration; + pending_commit_state()->visual_update_duration = base::TimeDelta(); + // If the parent sequence number has not advanced, then there is no need to // commit anything. This can occur when the child sequence number has // advanced. Which means that child has changed visual properites, and the @@ -1582,11 +1611,11 @@ void LayerTreeHost::AddLayerShouldPushProperties(Layer* layer) { } void LayerTreeHost::SetPageScaleFromImplSide(float page_scale) { - DCHECK(CommitRequested()); + DCHECK(syncing_deltas_for_test_ || CommitRequested()); // We should never process non-unit page_scale_delta for an OOPIF subframe. // TODO(wjmaclean): Remove this check as a pre-condition to closing the bug. // https://crbug.com/845097 - DCHECK(!settings_.is_layer_tree_for_subframe || + DCHECK(settings_.is_for_scalable_page || page_scale == pending_commit_state()->page_scale_factor) << "Setting PSF in oopif subframe: old psf = " << pending_commit_state()->page_scale_factor @@ -1597,7 +1626,7 @@ void LayerTreeHost::SetPageScaleFromImplSide(float page_scale) { void LayerTreeHost::SetElasticOverscrollFromImplSide( gfx::Vector2dF elastic_overscroll) { - DCHECK(CommitRequested()); + DCHECK(syncing_deltas_for_test_ || CommitRequested()); pending_commit_state()->elastic_overscroll = elastic_overscroll; } @@ -1704,6 +1733,9 @@ void LayerTreeHost::SetMutatorsNeedRebuildPropertyTrees() { void LayerTreeHost::SetElementFilterMutated(ElementId element_id, ElementListType list_type, const FilterOperations& filters) { + if (list_type != ElementListType::ACTIVE) + return; + if (IsUsingLayerLists()) { // In BlinkGenPropertyTrees/CompositeAfterPaint we always have property // tree nodes and can set the filter directly on the effect node. @@ -1721,6 +1753,9 @@ void LayerTreeHost::SetElementBackdropFilterMutated( ElementId element_id, ElementListType list_type, const FilterOperations& backdrop_filters) { + if (list_type != ElementListType::ACTIVE) + return; + if (IsUsingLayerLists()) { // In BlinkGenPropertyTrees/CompositeAfterPaint we always have property // tree nodes and can set the backdrop_filter directly on the effect node. @@ -1740,6 +1775,9 @@ void LayerTreeHost::SetElementOpacityMutated(ElementId element_id, DCHECK_GE(opacity, 0.f); DCHECK_LE(opacity, 1.f); + if (list_type != ElementListType::ACTIVE) + return; + if (IsUsingLayerLists()) { property_trees()->effect_tree_mutable().OnOpacityAnimated(element_id, opacity); @@ -1767,6 +1805,9 @@ void LayerTreeHost::SetElementTransformMutated( ElementId element_id, ElementListType list_type, const gfx::Transform& transform) { + if (list_type != ElementListType::ACTIVE) + return; + if (IsUsingLayerLists()) { property_trees()->transform_tree_mutable().OnTransformAnimated(element_id, transform); @@ -1921,12 +1962,6 @@ void LayerTreeHost::SetRenderFrameObserver( proxy_->SetRenderFrameObserver(std::move(observer)); } -void LayerTreeHost::SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) { - DCHECK(IsMainThread()); - proxy_->SetEnableFrameRateThrottling(enable_frame_rate_throttling); -} - void LayerTreeHost::SetDelegatedInkMetadata( std::unique_ptr<gfx::DelegatedInkMetadata> metadata) { pending_commit_state()->delegated_ink_metadata = std::move(metadata); @@ -1948,4 +1983,9 @@ uint32_t LayerTreeHost::GetAverageThroughput() const { return proxy_->GetAverageThroughput(); } +void LayerTreeHost::IncrementVisualUpdateDuration( + base::TimeDelta visual_update_duration) { + pending_commit_state()->visual_update_duration += visual_update_duration; +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index feccd6a65bd..abe129ddb22 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -441,10 +441,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { ->event_listener_properties[static_cast<size_t>(event_class)]; } - // Indicates that its acceptable to throttle the frame rate for this content - // to prioritize lower power/CPU use. - void SetEnableFrameRateThrottling(bool enable_frame_rate_throttling); - void SetViewportRectAndScale( const gfx::Rect& device_viewport_rect, float device_scale_factor, @@ -720,6 +716,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void NotifyThroughputTrackerResults(CustomTrackerResults results); void NotifyTransitionRequestsFinished( const std::vector<uint32_t>& sequence_ids); + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies); LayerTreeHostClient* client() { DCHECK(IsMainThread()); @@ -809,6 +807,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { return recording_scale_factor_; } + const ViewportPropertyIds& viewport_property_ids() const { + return pending_commit_state()->viewport_property_ids; + } + void SetSourceURL(ukm::SourceId source_id, const GURL& url); base::ReadOnlySharedMemoryRegion CreateSharedMemoryForSmoothnessUkm(); @@ -838,6 +840,23 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // Returns a percentage representing average throughput of last X seconds. uint32_t GetAverageThroughput() const; + // TODO(szager): Remove these once threaded compositing is enabled for all + // web_tests. + bool in_composite_for_test() const { return in_composite_for_test_; } + [[nodiscard]] base::AutoReset<bool> ForceSyncCompositeForTest() { + return base::AutoReset<bool>(&in_composite_for_test_, true); + } + + // Blink compositor unit tests sometimes want to simulate pushing deltas + // without going through the whole lifecycle to test the effects of the + // deltas. This flag turns off DCHECKs that deltas being set to main are + // during a commit phase so these tests can do this. + [[nodiscard]] base::AutoReset<bool> SimulateSyncingDeltasForTesting() { + return base::AutoReset<bool>(&syncing_deltas_for_test_, true); + } + + void IncrementVisualUpdateDuration(base::TimeDelta visual_update_duration); + protected: LayerTreeHost(InitParams params, CompositorMode mode); @@ -1015,6 +1034,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // for histograms. mutable bool waited_for_protected_sequence_ = false; + bool in_composite_for_test_ = false; + + bool syncing_deltas_for_test_ = false; + // Used to vend weak pointers to LayerTreeHost to ScopedDeferMainFrameUpdate // objects. base::WeakPtrFactory<LayerTreeHost> defer_main_frame_update_weak_ptr_factory_{ diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index 0e775a23e53..f52db87ce1a 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -6,10 +6,12 @@ #define CC_TREES_LAYER_TREE_HOST_CLIENT_H_ #include <memory> +#include <vector> #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "cc/input/browser_controls_state.h" +#include "cc/metrics/event_latency_tracker.h" #include "cc/metrics/frame_sequence_tracker_collection.h" #include "cc/trees/paint_holding_reason.h" #include "cc/trees/property_tree.h" @@ -188,6 +190,8 @@ class LayerTreeHostClient { // RecordEndOfFrameMetrics. virtual std::unique_ptr<BeginMainFrameMetrics> GetBeginMainFrameMetrics() = 0; virtual void NotifyThroughputTrackerResults(CustomTrackerResults results) = 0; + virtual void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) = 0; // Should only be implemented by Blink. virtual std::unique_ptr<WebVitalMetrics> GetWebVitalMetrics() = 0; @@ -203,9 +207,6 @@ class LayerTreeHostClient { // must be safe to use on both the compositor and main threads. class LayerTreeHostSchedulingClient { public: - // Indicates that the compositor thread scheduled a BeginMainFrame to run on - // the main thread. - virtual void DidScheduleBeginMainFrame() = 0; // Called unconditionally when BeginMainFrame runs on the main thread. virtual void DidRunBeginMainFrame() = 0; }; diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index 14e13169de8..aca208728d0 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -259,9 +259,6 @@ void RecordSourceIdConsistency(bool all_valid, bool all_unique) { } // namespace -DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeRasterDurationHistogramTimer, - "Scheduling.%s.PendingTreeRasterDuration") - void LayerTreeHostImpl::DidUpdateScrollAnimationCurve() { // Because we updated the animation target, notify the // `LatencyInfoSwapPromiseMonitor` to tell it that something happened that @@ -320,6 +317,11 @@ void LayerTreeHostImpl::SetNeedsFullViewportRedraw() { SetNeedsRedraw(); } +void LayerTreeHostImpl::SetDeferBeginMainFrame( + bool defer_begin_main_frame) const { + client_->SetDeferBeginMainFrameFromImpl(defer_begin_main_frame); +} + bool LayerTreeHostImpl::IsInHighLatencyMode() const { return impl_thread_phase_ == ImplThreadPhase::IDLE; } @@ -385,7 +387,9 @@ LayerTreeHostImpl::LayerTreeHostImpl( current_begin_frame_tracker_(FROM_HERE), compositor_frame_reporting_controller_( std::make_unique<CompositorFrameReportingController>( - /*should_report_metrics=*/!settings.single_thread_proxy_scheduler, + /*should_report_histograms=*/!settings + .single_thread_proxy_scheduler, + /*should_report_ukm=*/!settings.single_thread_proxy_scheduler, id)), settings_(settings), is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() && @@ -455,14 +459,16 @@ LayerTreeHostImpl::LayerTreeHostImpl( compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection( &frame_trackers_); -#if BUILDFLAG(IS_CHROMEOS_ASH) const bool is_ui = settings.is_layer_tree_for_ui; if (is_ui) { + compositor_frame_reporting_controller_->set_event_latency_tracker(this); + +#if BUILDFLAG(IS_CHROMEOS_ASH) dropped_frame_counter_.EnableReporForUI(); compositor_frame_reporting_controller_->SetThreadAffectsSmoothness( FrameInfo::SmoothEffectDrivingThread::kMain, true); - } #endif // BUILDFLAG(IS_CHROMEOS_ASH) + } dropped_frame_counter_.set_total_counter(&total_frame_counter_); frame_trackers_.set_custom_tracker_results_added_callback( @@ -522,11 +528,6 @@ const ThreadedInputHandler& LayerTreeHostImpl::GetInputHandler() const { return static_cast<const ThreadedInputHandler&>(*input_delegate_.get()); } -void LayerTreeHostImpl::WillSendBeginMainFrame() { - if (scheduling_client_) - scheduling_client_->DidScheduleBeginMainFrame(); -} - void LayerTreeHostImpl::DidSendBeginMainFrame(const viz::BeginFrameArgs& args) { frame_trackers_.NotifyBeginMainFrame(args); } @@ -586,12 +587,14 @@ void LayerTreeHostImpl::ReadyToCommit( } } -void LayerTreeHostImpl::BeginCommit(int source_frame_number) { +void LayerTreeHostImpl::BeginCommit(int source_frame_number, + uint64_t trace_id) { TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit"); if (!CommitToActiveTree()) CreatePendingTree(); sync_tree()->set_source_frame_number(source_frame_number); + sync_tree()->set_trace_id(trace_id); } // This function commits the LayerTreeHost, as represented by CommitState, to an @@ -719,6 +722,10 @@ void LayerTreeHostImpl::CommitComplete() { mutator_host_->HasSmilAnimation()) { frame_trackers_.StartSequence( FrameSequenceTrackerType::kMainThreadAnimation); + if (mutator_host_->HasSharedElementTransition()) { + frame_trackers_.StartSequence( + FrameSequenceTrackerType::kSETMainThreadAnimation); + } } for (const auto& info : mutator_host_->TakePendingThroughputTrackerInfos()) { @@ -750,8 +757,6 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() { // and the updated data for the image from the main frame. PaintImageIdFlatSet images_to_invalidate = tile_manager_.TakeImagesToInvalidateOnSyncTree(); - if (ukm_manager_) - ukm_manager_->AddCheckerboardedImages(images_to_invalidate.size()); const auto& animated_images = image_animation_controller_.AnimateForSyncTree(CurrentBeginFrameArgs()); @@ -914,10 +919,6 @@ void LayerTreeHostImpl::NotifyPendingTreeFullyPainted() { // Scheduler to wait for ReadyToDraw signal to avoid Checkerboard. if (CommitToActiveTree()) NotifyReadyToDraw(); - } else if (!CommitToActiveTree()) { - DCHECK(!pending_tree_raster_duration_timer_); - pending_tree_raster_duration_timer_ = - std::make_unique<PendingTreeRasterDurationHistogramTimer>(); } } @@ -1020,19 +1021,6 @@ void LayerTreeHostImpl::StartPageScaleAnimation(const gfx::Point& target_offset, 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; @@ -1308,8 +1296,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { int num_missing_tiles = 0; int num_incomplete_tiles = 0; int64_t checkerboarded_no_recording_content_area = 0; - int64_t checkerboarded_needs_raster_content_area = 0; - int64_t total_visible_area = 0; + bool have_copy_request = active_tree()->property_trees()->effect_tree().HasCopyRequests(); bool have_missing_animated_tiles = false; @@ -1389,9 +1376,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { num_incomplete_tiles += append_quads_data.num_incomplete_tiles; checkerboarded_no_recording_content_area += append_quads_data.checkerboarded_no_recording_content_area; - checkerboarded_needs_raster_content_area += - append_quads_data.checkerboarded_needs_raster_content_area; - total_visible_area += append_quads_data.visible_layer_area; + if (append_quads_data.num_missing_tiles > 0) { have_missing_animated_tiles |= layer->screen_space_transform_is_animating(); @@ -1490,30 +1475,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { frame->has_missing_content = num_missing_tiles > 0 || num_incomplete_tiles > 0; - if (ukm_manager_) { - ukm_manager_->AddCheckerboardStatsForFrame( - checkerboarded_no_recording_content_area + - checkerboarded_needs_raster_content_area, - num_missing_tiles, total_visible_area); - } - - if (active_tree_->has_ever_been_drawn()) { - UMA_HISTOGRAM_COUNTS_100( - "Compositing.RenderPass.AppendQuadData.NumMissingTiles", - num_missing_tiles); - UMA_HISTOGRAM_COUNTS_100( - "Compositing.RenderPass.AppendQuadData.NumIncompleteTiles", - num_incomplete_tiles); - UMA_HISTOGRAM_COUNTS_1M( - "Compositing.RenderPass.AppendQuadData." - "CheckerboardedNoRecordingContentArea", - checkerboarded_no_recording_content_area); - UMA_HISTOGRAM_COUNTS_1M( - "Compositing.RenderPass.AppendQuadData." - "CheckerboardedNeedRasterContentArea", - checkerboarded_needs_raster_content_area); - } - TRACE_EVENT_END2("cc,benchmark", "LayerTreeHostImpl::CalculateRenderPasses", "draw_result", draw_result, "missing tiles", num_missing_tiles); @@ -1547,11 +1508,6 @@ void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) { viewport_damage_rect_.Union(damage_rect); } -void LayerTreeHostImpl::SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) { - enable_frame_rate_throttling_ = enable_frame_rate_throttling; -} - void LayerTreeHostImpl::InvalidateContentOnImplSide() { DCHECK(!pending_tree_); // Invalidation should never be ran outside the impl frame for non @@ -1750,7 +1706,9 @@ void LayerTreeHostImpl::EvictTexturesForTesting() { UpdateTileManagerMemoryPolicy(ManagedMemoryPolicy(0)); } -void LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting(bool block) { +void LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting( + bool block, + bool notify_if_blocked) { NOTREACHED(); } @@ -1923,24 +1881,23 @@ TargetColorParams LayerTreeHostImpl::GetTargetColorParams( if (!hdr_color_space.IsValid()) return params; - // It's expensive to rasterize in HDR, so we only want to do so when we know - // we have HDR content to rasterize. - if (hdr_color_space.IsHDR() && - content_color_usage != gfx::ContentColorUsage::kHDR) { - params.color_space = gfx::ColorSpace::CreateDisplayP3D65(); - return params; - } + if (hdr_color_space.IsHDR()) { + if (content_color_usage == gfx::ContentColorUsage::kHDR) { + // Rasterization of HDR content is always done in extended-sRGB space. + params.color_space = gfx::ColorSpace::CreateExtendedSRGB(); - // The raster color space should contain sRGB to avoid artifacts during - // rasterization. - if (CheckColorSpaceContainsSrgb(hdr_color_space)) { - params.color_space = hdr_color_space; + // Only report the HDR capabilities if they are requested. + params.hdr_max_luminance_relative = + display_cs.GetHDRMaxLuminanceRelative(); + } else { + // If the content is not HDR, then use Display P3 as the rasterization + // color space. + params.color_space = gfx::ColorSpace::CreateDisplayP3D65(); + } + return params; } - // Only report the HDR capabilities if they are requested. - if (content_color_usage == gfx::ContentColorUsage::kHDR) - params.hdr_max_luminance_relative = display_cs.GetHDRMaxLuminanceRelative(); - + params.color_space = hdr_color_space; return params; } @@ -2005,7 +1962,6 @@ void LayerTreeHostImpl::NotifyReadyToActivate() { // than wait for the TileManager to actually raster the content! if (!pending_tree_fully_painted_) return; - pending_tree_raster_duration_timer_.reset(); client_->NotifyReadyToActivate(); } @@ -2186,23 +2142,6 @@ void LayerTreeHostImpl::ReclaimResources( // In OOM, we now might be able to release more resources that were held // because they were exported. if (resource_pool_) { - if (resource_pool_->memory_usage_bytes()) { - const size_t kMegabyte = 1024 * 1024; - // This is a good time to log memory usage. A chunk of work has just - // completed but none of the memory used for that work has likely been - // freed. - std::string client_suffix; - if (settings_.commit_to_active_tree) { - client_suffix = "Browser"; - } else if (settings_.is_layer_tree_for_subframe) { - client_suffix = "OOPIF"; - } else { - client_suffix = "Renderer"; - } - base::UmaHistogramMemoryMB( - "Compositing.ResourcePoolMemoryUsage." + client_suffix, - static_cast<int>(resource_pool_->memory_usage_bytes() / kMegabyte)); - } resource_pool_->ReduceResourceUsage(); } @@ -2276,6 +2215,11 @@ void LayerTreeHostImpl::OnCompositorFrameTransitionDirectiveProcessed( SetNeedsCommit(); } +void LayerTreeHostImpl::ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) { + client_->ReportEventLatency(std::move(latencies)); +} + void LayerTreeHostImpl::OnCanDrawStateChangedForTree() { client_->OnCanDrawStateChanged(CanDraw()); } @@ -2469,6 +2413,14 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata( child_local_surface_id_allocator_.GetCurrentLocalSurfaceId(); } + metadata.previous_surfaces_visual_update_duration = + active_tree()->previous_surfaces_visual_update_duration(); + metadata.current_surface_visual_update_duration = + active_tree()->visual_update_duration(); + // We only want to report the durations from a Commit the first time. Not for + // subsequent Impl-only frames. + active_tree()->ClearVisualUpdateDurations(); + return metadata; } @@ -2516,9 +2468,15 @@ absl::optional<LayerTreeHostImpl::SubmitInfo> LayerTreeHostImpl::DrawLayers( } base::TimeTicks submit_time = base::TimeTicks::Now(); - layer_tree_frame_sink_->SubmitCompositorFrame( - std::move(compositor_frame), - /*hit_test_data_changed=*/false); + { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.SubmitCompositorFrame", + TRACE_ID_GLOBAL(active_tree()->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + layer_tree_frame_sink_->SubmitCompositorFrame( + std::move(compositor_frame), + /*hit_test_data_changed=*/false); + } #if DCHECK_IS_ON() if (!doing_sync_draw_) { @@ -2554,6 +2512,11 @@ absl::optional<LayerTreeHostImpl::SubmitInfo> LayerTreeHostImpl::DrawLayers( !mutator_host_->HasSmilAnimation()) { frame_trackers_.StopSequence( FrameSequenceTrackerType::kMainThreadAnimation); + frame_trackers_.StopSequence( + FrameSequenceTrackerType::kSETMainThreadAnimation); + } else if (!mutator_host_->HasSharedElementTransition()) { + frame_trackers_.StopSequence( + FrameSequenceTrackerType::kSETMainThreadAnimation); } if (lcd_text_metrics_reporter_) { @@ -2575,7 +2538,6 @@ absl::optional<LayerTreeHostImpl::SubmitInfo> LayerTreeHostImpl::DrawLayers( } active_tree_->ResetAllChangeTracking(); - active_tree_->set_has_ever_been_drawn(true); devtools_instrumentation::DidDrawFrame( id_, frame->begin_frame_ack.frame_id.sequence_number); benchmark_instrumentation::IssueImplThreadRenderingStatsEvent( @@ -2595,6 +2557,7 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( TRACE_ID_GLOBAL(CurrentBeginFrameArgs().trace_id), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", "GenerateCompositorFrame"); + rendering_stats_instrumentation_->IncrementFrameCount(1); memory_history_->SaveEntry(tile_manager_.memory_stats_from_last_assign()); @@ -2686,13 +2649,11 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( constexpr auto kTwiceOfDefaultInterval = viz::BeginFrameArgs::DefaultInterval() * 2; constexpr auto kMinDelta = kTwiceOfDefaultInterval - kFudgeDelta; - if (enable_frame_rate_throttling_) { - metadata.preferred_frame_interval = viz::BeginFrameArgs::MaxInterval(); - } else if (mutator_host_->MainThreadAnimationsCount() == 0 && - !mutator_host_->HasSmilAnimation() && - mutator_host_->NeedsTickAnimations() && - !frame_rate_estimator_.input_priority_mode() && - mutator_host_->MinimumTickInterval() > kMinDelta) { + if (mutator_host_->MainThreadAnimationsCount() == 0 && + !mutator_host_->HasSmilAnimation() && + mutator_host_->NeedsTickAnimations() && + !frame_rate_estimator_.input_priority_mode() && + mutator_host_->MinimumTickInterval() > kMinDelta) { // All animations are impl-thread animations that tick at no more than // half the default display compositing fps. // Here and below with FrameRateEstimator::GetPreferredInterval(), the @@ -3327,12 +3288,6 @@ void LayerTreeHostImpl::ActivateSyncTree() { pending_tree_->local_surface_id_from_parent().ToString()); active_tree_->lifecycle().AdvanceTo(LayerTreeLifecycle::kBeginningSync); - // In most cases, this will be reset in NotifyReadyToActivate, since we - // activate the pending tree only when its ready. But an activation may be - // forced, in the case of a context loss for instance, so reset it here as - // well. - pending_tree_raster_duration_timer_.reset(); - // Process any requests in the UI resource queue. The request queue is // given in LayerTreeHost::FinishCommit. This must take place before the // swap. @@ -4169,7 +4124,7 @@ LayerTreeHostImpl::ProcessCompositorDeltas() { // We should never process non-unit page_scale_delta for an OOPIF subframe. // TODO(wjmaclean): Remove this DCHECK as a pre-condition to closing the bug. // https://crbug.com/845097 - DCHECK(!settings().is_layer_tree_for_subframe || + DCHECK(settings().is_for_scalable_page || commit_data->page_scale_delta == 1.f); commit_data->top_controls_delta = active_tree()->top_controls_shown_ratio()->PullDeltaForMainThread(); @@ -4290,6 +4245,14 @@ bool LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time, FrameSequenceTrackerType::kCompositorAnimation); } + if (animated && mutator_host_->HasSharedElementTransition()) { + frame_trackers_.StartSequence( + FrameSequenceTrackerType::kSETCompositorAnimation); + } else { + frame_trackers_.StopSequence( + FrameSequenceTrackerType::kSETCompositorAnimation); + } + // TODO(crbug.com/551138): We could return true only if the animations are on // the active tree. There's no need to cause a draw to take place from // animations starting/ticking on the pending tree. @@ -4333,6 +4296,13 @@ void LayerTreeHostImpl::RegisterScrollbarAnimationController( scrollbar_opacity); } +void LayerTreeHostImpl::DidRegisterScrollbarLayer( + ElementId scroll_element_id, + ScrollbarOrientation orientation) { + if (input_delegate_) + input_delegate_->DidRegisterScrollbar(scroll_element_id, orientation); +} + void LayerTreeHostImpl::DidUnregisterScrollbarLayer( ElementId scroll_element_id, ScrollbarOrientation orientation) { @@ -4404,6 +4374,10 @@ ScrollbarSet LayerTreeHostImpl::ScrollbarsFor(ElementId id) const { return active_tree_->ScrollbarsFor(id); } +bool LayerTreeHostImpl::IsFluentScrollbar() const { + return settings().enable_fluent_scrollbar; +} + void LayerTreeHostImpl::AddVideoFrameController( VideoFrameController* controller) { bool was_empty = video_frame_controllers_.empty(); @@ -5152,6 +5126,15 @@ void LayerTreeHostImpl::RequestInvalidationForAnimatedImages() { client_->NeedsImplSideInvalidation(needs_first_draw_on_activation); } +bool LayerTreeHostImpl::IsReadyToActivate() const { + return client_->IsReadyToActivate(); +} + +void LayerTreeHostImpl::RequestImplSideInvalidationForRerasterTiling() { + bool needs_first_draw_on_activation = true; + client_->NeedsImplSideInvalidation(needs_first_draw_on_activation); +} + base::WeakPtr<LayerTreeHostImpl> LayerTreeHostImpl::AsWeakPtr() { return weak_factory_.GetWeakPtr(); } diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index 782a3c0de89..1b985be80c6 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -32,6 +32,7 @@ #include "cc/layers/layer_collections.h" #include "cc/metrics/average_lag_tracking_manager.h" #include "cc/metrics/dropped_frame_counter.h" +#include "cc/metrics/event_latency_tracker.h" #include "cc/metrics/event_metrics.h" #include "cc/metrics/events_metrics_manager.h" #include "cc/metrics/frame_sequence_tracker_collection.h" @@ -92,7 +93,6 @@ class MemoryHistory; class MutatorEvents; class MutatorHost; class PageScaleAnimation; -class PendingTreeRasterDurationHistogramTimer; class RasterTilePriorityQueue; class RasterBufferProvider; class RasterQueryQueue; @@ -119,6 +119,7 @@ class LayerTreeHostImplClient { virtual void DidReceiveCompositorFrameAckOnImplThread() = 0; virtual void OnCanDrawStateChanged(bool can_draw) = 0; virtual void NotifyReadyToActivate() = 0; + virtual bool IsReadyToActivate() = 0; virtual void NotifyReadyToDraw() = 0; // Please call these 2 functions through // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsOneBeginImplFrame(). @@ -127,6 +128,7 @@ class LayerTreeHostImplClient { virtual void SetNeedsCommitOnImplThread() = 0; virtual void SetNeedsPrepareTilesOnImplThread() = 0; virtual void SetVideoNeedsBeginFrames(bool needs_begin_frames) = 0; + virtual void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) = 0; virtual bool IsInsideDraw() = 0; virtual void RenewTreePriority() = 0; virtual void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task, @@ -180,6 +182,9 @@ class LayerTreeHostImplClient { virtual size_t CommitDurationSampleCountForTesting() const = 0; + virtual void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) = 0; + protected: virtual ~LayerTreeHostImplClient() = default; }; @@ -193,7 +198,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, public VideoFrameControllerClient, public MutatorHostClient, public ImageAnimationController::Client, - public CompositorDelegateForInput { + public CompositorDelegateForInput, + public EventLatencyTracker { public: // This structure is used to build all the state required for producing a // single CompositorFrame. The |render_passes| list becomes the set of @@ -318,7 +324,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, return viewport_damage_rect_; } - virtual void WillSendBeginMainFrame(); + virtual void WillSendBeginMainFrame() {} virtual void DidSendBeginMainFrame(const viz::BeginFrameArgs& args); virtual void BeginMainFrameAborted( CommitEarlyOutReason reason, @@ -329,7 +335,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, const viz::BeginFrameArgs& commit_args, const BeginMainFrameMetrics* begin_main_frame_metrics, bool commit_timeout = false); - virtual void BeginCommit(int source_frame_number); + virtual void BeginCommit(int source_frame_number, uint64_t trace_id); virtual void FinishCommit(CommitState& commit_state, const ThreadUnsafeCommitState& unsafe_state); virtual void CommitComplete(); @@ -343,7 +349,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, void DidAnimateScrollOffset(); void SetFullViewportDamage(); void SetViewportDamage(const gfx::Rect& damage_rect); - void SetEnableFrameRateThrottling(bool enable_frame_rate_throttling); // Interface for ThreadedInputHandler void BindToInputHandler( @@ -371,6 +376,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, const LayerTreeSettings& GetSettings() const override; LayerTreeHostImpl& GetImplDeprecated() override; const LayerTreeHostImpl& GetImplDeprecated() const override; + void SetDeferBeginMainFrame(bool defer_begin_main_frame) const override; bool CanInjectJankOnMain() const; FrameSequenceTrackerCollection& frame_trackers() { return frame_trackers_; } @@ -481,8 +487,11 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, // When blocking, this prevents client_->NotifyReadyToActivate() from being // called. When disabled, it calls client_->NotifyReadyToActivate() - // immediately if any notifications had been blocked while blocking. - virtual void BlockNotifyReadyToActivateForTesting(bool block); + // immediately if any notifications had been blocked while blocking and + // notify_if_blocked is true. + virtual void BlockNotifyReadyToActivateForTesting( + bool block, + bool notify_if_blocked = true); // Prevents notifying the |client_| when an impl side invalidation request is // made. When unblocked, the disabled request will immediately be called. @@ -495,6 +504,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, void RegisterScrollbarAnimationController(ElementId scroll_element_id, float initial_opacity); + void DidRegisterScrollbarLayer(ElementId scroll_element_id, + ScrollbarOrientation orientation); void DidUnregisterScrollbarLayer(ElementId scroll_element_id, ScrollbarOrientation orientation); ScrollbarAnimationController* ScrollbarAnimationControllerForElementId( @@ -535,6 +546,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, void SetNeedsRedrawForScrollbarAnimation() override; ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override; void DidChangeScrollbarVisibility() override; + bool IsFluentScrollbar() const override; // VideoBeginFrameSource implementation. void AddVideoFrameController(VideoFrameController* controller) override; @@ -561,6 +573,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, void OnCompositorFrameTransitionDirectiveProcessed( uint32_t sequence_id) override; + // EventLatencyTracker implementation. + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) override; + // Called from LayerTreeImpl. void OnCanDrawStateChangedForTree(); @@ -879,6 +895,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, return throttle_decider_.ids(); } + bool IsReadyToActivate() const; + + void RequestImplSideInvalidationForRerasterTiling(); + protected: LayerTreeHostImpl( const LayerTreeSettings& settings, @@ -1181,9 +1201,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, bool may_throttle_if_undrawn_frames_ = true; - std::unique_ptr<PendingTreeRasterDurationHistogramTimer> - pending_tree_raster_duration_timer_; - // These completion states to be transfered to the main thread when we // begin main frame. The pair represents a request id and the completion (ie // success) state. @@ -1270,8 +1287,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient, FrameRateEstimator frame_rate_estimator_; bool has_observed_first_scroll_delay_ = false; - bool enable_frame_rate_throttling_ = false; - // True if we are measuring smoothness in TotalFrameCounter and // DroppedFrameCounter. Currently true when first contentful paint is done. bool is_measuring_smoothness_ = false; diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index f7bca00a04a..3b1e8aa5ed6 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -83,7 +83,6 @@ #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/region_capture_bounds.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" @@ -215,6 +214,11 @@ class LayerTreeHostImplTest : public testing::Test, did_notify_ready_to_activate_ = true; host_impl_->ActivateSyncTree(); } + bool IsReadyToActivate() override { + // in NotifyReadyToActivate(), call ActivateSyncTree() directly + // so this is always false + return false; + } void NotifyReadyToDraw() override {} void SetNeedsRedrawOnImplThread() override { did_request_redraw_ = true; } void SetNeedsOneBeginImplFrameOnImplThread() override { @@ -225,6 +229,7 @@ class LayerTreeHostImplTest : public testing::Test, } void SetNeedsCommitOnImplThread() override { did_request_commit_ = true; } void SetVideoNeedsBeginFrames(bool needs_begin_frames) override {} + void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override {} bool IsInsideDraw() override { return false; } void RenewTreePriority() override {} void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task, @@ -272,6 +277,8 @@ class LayerTreeHostImplTest : public testing::Test, void NotifyPaintWorkletStateChange( Scheduler::PaintWorkletState state) override {} void NotifyThroughputTrackerResults(CustomTrackerResults results) override {} + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) override {} void DidObserveFirstScrollDelay( base::TimeDelta first_scroll_delay, @@ -674,7 +681,7 @@ class LayerTreeHostImplTest : public testing::Test, FakeRasterSource::CreateFromRecordingSource(recording_source.get()); // Create the pending tree. - host_impl_->BeginCommit(0); + host_impl_->BeginCommit(0, /*trace_id=*/1); LayerTreeImpl* pending_tree = host_impl_->pending_tree(); LayerImpl* root = SetupRootLayer<FakePictureLayerImpl>( pending_tree, layer_size, raster_source); @@ -3485,7 +3492,6 @@ class MissingTilesLayer : public LayerImpl { AppendQuadsData* append_quads_data) override { append_quads_data->num_missing_tiles += 10; append_quads_data->checkerboarded_no_recording_content_area += 200; - append_quads_data->checkerboarded_needs_raster_content_area += 200; append_quads_data->visible_layer_area += 200; } }; @@ -4407,9 +4413,11 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, SyncSubpixelScrollDelta) { // Verify this scroll delta is consistent with the snapped position of the // scroll layer. - draw_property_utils::ComputeTransforms(&scroll_layer->layer_tree_impl() - ->property_trees() - ->transform_tree_mutable()); + draw_property_utils::ComputeTransforms( + &scroll_layer->layer_tree_impl() + ->property_trees() + ->transform_tree_mutable(), + scroll_layer->layer_tree_impl()->viewport_property_ids()); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0, -19), scroll_layer->ScreenSpaceTransform().To2dTranslation()); } @@ -6242,7 +6250,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, auto* layer = AddLayer<SolidColorLayerImpl>(host_impl_->active_tree()); layer->SetBounds(gfx::Size(10, 10)); layer->SetDrawsContent(true); - layer->SetBackgroundColor(SK_ColorRED); + layer->SetBackgroundColor(SkColors::kRed); CopyProperties(root, layer); UpdateDrawProperties(host_impl_->active_tree()); @@ -11043,7 +11051,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PartialSwapReceivesDamageRect) { layer_tree_host_impl->active_tree()->SetDeviceViewportRect(gfx::Rect(10, 10)); // This will damage everything. - root->SetBackgroundColor(SK_ColorBLACK); + root->SetBackgroundColor(SkColors::kBlack); args = viz::CreateBeginFrameArgsForTesting( BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, base::TimeTicks() + base::Milliseconds(1)); @@ -11250,13 +11258,13 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, FrameIncludesDamageRect) { auto* root = SetupRootLayer<SolidColorLayerImpl>(host_impl_->active_tree(), gfx::Size(10, 10)); root->SetDrawsContent(true); - root->SetBackgroundColor(SK_ColorRED); + root->SetBackgroundColor(SkColors::kRed); // Child layer is in the bottom right corner. auto* child = AddLayer<SolidColorLayerImpl>(host_impl_->active_tree()); child->SetBounds(gfx::Size(1, 1)); child->SetDrawsContent(true); - child->SetBackgroundColor(SK_ColorRED); + child->SetBackgroundColor(SkColors::kRed); CopyProperties(root, child); child->SetOffsetToTransformParent(gfx::Vector2dF(9, 9)); @@ -11278,11 +11286,6 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, FrameIncludesDamageRect) { DrawFrameAndTestDamage(no_damage, child); } -class GLRendererWithSetupQuadForAntialiasing : public viz::GLRenderer { - public: - using viz::GLRenderer::ShouldAntialiasQuad; -}; - TEST_P(ScrollUnifiedLayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { // Due to precision issues (especially on Android), sometimes far // away quads can end up thinking they need AA. @@ -11334,16 +11337,12 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { ASSERT_LE(1u, frame.render_passes[0]->quad_list.size()); const viz::DrawQuad* quad = frame.render_passes[0]->quad_list.front(); - bool clipped = false, force_aa = false; - gfx::QuadF device_layer_quad = MathUtil::MapQuad( + bool clipped = false; + MathUtil::MapQuad( quad->shared_quad_state->quad_to_target_transform, gfx::QuadF(gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)), &clipped); EXPECT_FALSE(clipped); - bool antialiased = - GLRendererWithSetupQuadForAntialiasing::ShouldAntialiasQuad( - device_layer_quad, clipped, force_aa); - EXPECT_FALSE(antialiased); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -11530,7 +11529,7 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, LayerImpl* root = SetupRootLayer<SolidColorLayerImpl>( host_impl_->active_tree(), gfx::Size(10, 10)); - root->SetBackgroundColor(SK_ColorRED); + root->SetBackgroundColor(SkColors::kRed); UpdateDrawProperties(host_impl_->active_tree()); // RequiresHighResToDraw is set when new output surface is used. @@ -11651,108 +11650,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, CreateETC1UIResource) { EXPECT_NE(viz::kInvalidResourceId, id1); } -class FrameSinkClient : public TestLayerTreeFrameSinkClient { - public: - explicit FrameSinkClient( - scoped_refptr<viz::ContextProvider> display_context_provider) - : display_context_provider_(std::move(display_context_provider)) {} - - std::unique_ptr<viz::DisplayCompositorMemoryAndTaskController> - CreateDisplayController() override { - // In this implementation, no output surface has a real gpu thread, and - // there is no overlay support. - return nullptr; - } - std::unique_ptr<viz::SkiaOutputSurface> CreateDisplaySkiaOutputSurface( - viz::DisplayCompositorMemoryAndTaskController*) override { - return viz::FakeSkiaOutputSurface::Create3d( - std::move(display_context_provider_)); - } - - std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurface( - scoped_refptr<viz::ContextProvider> compositor_context_provider) - override { - return viz::FakeOutputSurface::Create3d( - std::move(display_context_provider_)); - } - - void DisplayReceivedLocalSurfaceId( - const viz::LocalSurfaceId& local_surface_id) override {} - void DisplayReceivedCompositorFrame( - const viz::CompositorFrame& frame) override {} - void DisplayWillDrawAndSwap( - bool will_draw_and_swap, - viz::AggregatedRenderPassList* render_passes) override {} - void DisplayDidDrawAndSwap() override {} - - private: - scoped_refptr<viz::ContextProvider> display_context_provider_; -}; - -using LayerTreeHostImplTestWithRenderer = LayerTreeHostImplTest; - -TEST_F(LayerTreeHostImplTestWithRenderer, ShutdownReleasesContext) { - viz::DebugRendererSettings debug_settings; - - scoped_refptr<viz::TestContextProvider> context_provider = - viz::TestContextProvider::Create(); - FrameSinkClient test_client(context_provider); - - constexpr bool synchronous_composite = true; - constexpr bool disable_display_vsync = false; - constexpr double refresh_rate = 60.0; - std::unique_ptr<TaskRunnerProvider> task_runner_provider = - TaskRunnerProvider::Create(base::ThreadTaskRunnerHandle::Get(), nullptr); - auto layer_tree_frame_sink = std::make_unique<TestLayerTreeFrameSink>( - context_provider, viz::TestContextProvider::CreateWorker(), nullptr, - viz::RendererSettings(), &debug_settings, task_runner_provider.get(), - synchronous_composite, disable_display_vsync, refresh_rate); - layer_tree_frame_sink->SetClient(&test_client); - - CreateHostImpl(DefaultSettings(), std::move(layer_tree_frame_sink)); - - LayerImpl* root = SetupDefaultRootLayer(gfx::Size(10, 10)); - struct Helper { - std::unique_ptr<viz::CopyOutputResult> unprocessed_result; - void OnResult(base::OnceClosure finished, - std::unique_ptr<viz::CopyOutputResult> result) { - unprocessed_result = std::move(result); - std::move(finished).Run(); - } - } helper; - - GetEffectNode(root)->has_copy_request = true; - base::RunLoop copy_request_run_loop; - GetPropertyTrees(root)->effect_tree_mutable().AddCopyRequest( - root->effect_tree_index(), - std::make_unique<viz::CopyOutputRequest>( - viz::CopyOutputRequest::ResultFormat::RGBA, - viz::CopyOutputRequest::ResultDestination::kNativeTextures, - base::BindOnce(&Helper::OnResult, base::Unretained(&helper), - copy_request_run_loop.QuitClosure()))); - DrawFrame(); - - auto* sii = context_provider->SharedImageInterface(); - // The CopyOutputResult has a ref on the viz::ContextProvider and a shared - // image allocated. - copy_request_run_loop.Run(); - EXPECT_TRUE(helper.unprocessed_result); - EXPECT_FALSE(context_provider->HasOneRef()); - EXPECT_EQ(1u, sii->shared_image_count()); - - host_impl_->ReleaseLayerTreeFrameSink(); - host_impl_ = nullptr; - - // The texture release callback that was given to the CopyOutputResult has - // been canceled, and the shared image deleted. - EXPECT_TRUE(context_provider->HasOneRef()); - EXPECT_EQ(0u, sii->shared_image_count()); - - // When resetting the CopyOutputResult, it will run its texture release - // callback. This should not cause a crash, etc. - helper.unprocessed_result.reset(); -} - // This tests the case where hit testing only on scrollable layers returns a // layer that's outside the scroll chain of the first hit test *any* layer. See // LayerTreeHostImpl::IsInitialScrollHitTestReliable for details. @@ -13729,6 +13626,65 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, host_impl_ = nullptr; } +// Tests that no scrolls occur when thumb_len equals track_len. +TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollOnLargeThumb) { + LayerTreeSettings settings = DefaultSettings(); + settings.compositor_threaded_scrollbar_scrolling = true; + CreateHostImpl(settings, CreateLayerTreeFrameSink()); + + // Setup the viewport. + const gfx::Size viewport_size = gfx::Size(360, 600); + const gfx::Size content_size = gfx::Size(345, 3800); + SetupViewportLayersOuterScrolls(viewport_size, content_size); + LayerImpl* scroll_layer = OuterViewportScrollLayer(); + + // Set up the scrollbar and its dimensions. + LayerTreeImpl* layer_tree_impl = host_impl_->active_tree(); + layer_tree_impl->set_painted_device_scale_factor(2.5f); + auto* scrollbar = AddLayer<PaintedScrollbarLayerImpl>( + layer_tree_impl, ScrollbarOrientation::VERTICAL, false, true); + SetupScrollbarLayerCommon(scroll_layer, scrollbar); + scrollbar->SetHitTestable(true); + + const gfx::Size scrollbar_size = gfx::Size(15, 600); + scrollbar->SetBounds(scrollbar_size); + + // Set up the thumb dimensions. + scrollbar->SetThumbThickness(15); + scrollbar->SetThumbLength(575); + scrollbar->SetTrackRect(gfx::Rect(0, 15, 15, 575)); + scrollbar->SetOffsetToTransformParent(gfx::Vector2dF(345, 0)); + + TestInputHandlerClient input_handler_client; + GetInputHandler().BindToClient(&input_handler_client); + + // PointerDown on the scrollbar should populate drag_state. + GetInputHandler().MouseDown(gfx::PointF(350, 300), + /*jump_key_modifier*/ false); + EXPECT_TRUE(GetInputHandler() + .scrollbar_controller_for_testing() + ->drag_state_.has_value()); + + // Moving the mouse downwards should result in no scroll. + InputHandlerPointerResult res = + GetInputHandler().MouseMoveAt(gfx::Point(350, 600)); + EXPECT_EQ(res.scroll_delta.y(), 0); + + // Moving the mouse upwards should result in no scroll. + res = GetInputHandler().MouseMoveAt(gfx::Point(350, 0)); + EXPECT_EQ(res.scroll_delta.y(), 0); + + // End the scroll. + GetInputHandler().MouseUp(gfx::PointF(350, 0)); + EXPECT_TRUE(!GetInputHandler() + .scrollbar_controller_for_testing() + ->drag_state_.has_value()); + + // Tear down the LayerTreeHostImpl before the InputHandlerClient. + host_impl_->ReleaseLayerTreeFrameSink(); + host_impl_ = nullptr; +} + // Tests that deleting a horizontal scrollbar doesn't affect the autoscroll task // for the vertical scrollbar. TEST_P(ScrollUnifiedLayerTreeHostImplTest, AutoscrollOnDeletedScrollbar) { @@ -13777,12 +13733,45 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, AutoscrollOnDeletedScrollbar) { ->AutoscrollTaskIsScheduled()); // If a call comes in to delete the scrollbar layer for which the autoscroll - // was scheduled, the autoscroll task should be cancelled. - host_impl_->DidUnregisterScrollbarLayer(scroll_layer->element_id(), - ScrollbarOrientation::VERTICAL); - EXPECT_FALSE(GetInputHandler() - .scrollbar_controller_for_testing() - ->AutoscrollTaskIsScheduled()); + // was scheduled, the autoscroll task should set a waiting state instead of + // initiating an autoscroll, in case the scrollbar comes back. + layer_tree_impl->UnregisterScrollbar(scrollbar); + + EXPECT_TRUE(GetInputHandler() + .scrollbar_controller_for_testing() + ->AutoscrollTaskIsScheduled()); + + GetInputHandler() + .scrollbar_controller_for_testing() + ->cancelable_autoscroll_task_->callback() + .Run(); + GetInputHandler() + .scrollbar_controller_for_testing() + ->cancelable_autoscroll_task_.reset(); + EXPECT_EQ(GetInputHandler() + .scrollbar_controller_for_testing() + ->autoscroll_state_->status, + ScrollbarController::AutoScrollStatus::AUTOSCROLL_READY); + + // Re-register the scrollbar. An autoscroll task should be posted that + // actually starts a scroll animation + layer_tree_impl->RegisterScrollbar(scrollbar); + + EXPECT_TRUE(GetInputHandler() + .scrollbar_controller_for_testing() + ->AutoscrollTaskIsScheduled()); + + GetInputHandler() + .scrollbar_controller_for_testing() + ->cancelable_autoscroll_task_->callback() + .Run(); + GetInputHandler() + .scrollbar_controller_for_testing() + ->cancelable_autoscroll_task_.reset(); + EXPECT_EQ(GetInputHandler() + .scrollbar_controller_for_testing() + ->autoscroll_state_->status, + ScrollbarController::AutoScrollStatus::AUTOSCROLL_SCROLLING); // End the scroll. GetInputHandler().MouseUp(gfx::PointF(350, 580)); @@ -14336,9 +14325,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragAfterJumpClick) { scrollbar->SetBounds(scrollbar_size); host_impl_->set_force_smooth_wheel_scrolling_for_testing(true); + const int thumb_len = 50; // Set up the thumb dimensions. scrollbar->SetThumbThickness(15); - scrollbar->SetThumbLength(50); + scrollbar->SetThumbLength(thumb_len); scrollbar->SetTrackRect(gfx::Rect(0, 15, 15, 575)); // Set up scrollbar arrows. @@ -14371,11 +14361,17 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragAfterJumpClick) { .scrollbar_controller_for_testing() ->drag_state_.has_value()); - // This verifies that the jump click delta was accounted for correctly. + // This verifies that the start/snap-back position is the scroll position + // before any jump-click EXPECT_FLOAT_EQ(GetInputHandler() .scrollbar_controller_for_testing() ->drag_state_->scroll_position_at_start_, - 243.80952f); + 0.0f); + + EXPECT_FLOAT_EQ(GetInputHandler() + .scrollbar_controller_for_testing() + ->drag_state_->drag_origin.y(), + 15.0f + thumb_len / 2.0f); } // Tear down the LayerTreeHostImpl before the InputHandlerClient. @@ -14454,10 +14450,16 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, // existing scroll offset animations are aborted and a new autoscroll // animation is created. Test passes if unit test doesn't hit any DCHECK // failures. + GetInputHandler().scrollbar_controller_for_testing()->autoscroll_state_ = + ScrollbarController::AutoScrollState(); + GetInputHandler() + .scrollbar_controller_for_testing() + ->autoscroll_state_->velocity = 800; GetInputHandler() .scrollbar_controller_for_testing() - ->StartAutoScrollAnimation(/*scroll_velocity*/ 800, - ScrollbarPart::FORWARD_TRACK); + ->autoscroll_state_->pressed_scrollbar_part = + ScrollbarPart::FORWARD_TRACK; + GetInputHandler().scrollbar_controller_for_testing()->StartAutoScroll(); EXPECT_TRUE(GetImplAnimationHost()->ImplOnlyScrollAnimatingElement()); } @@ -15797,7 +15799,7 @@ TEST_F(MsaaCompatibilityLayerTreeHostImplTest, } TEST_P(ScrollUnifiedLayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) { - // Check page scale factor update in property trees when an update is made + // Check page scale factor updates the property trees when an update is made // on the active tree. CreatePendingTree(); host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 3); @@ -15816,20 +15818,26 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) { EXPECT_EQ(gfx::Vector2dF(2, 2), active_tree_node->local.To2dScale()); EXPECT_EQ(gfx::Point3F(), active_tree_node->origin); EXPECT_EQ(2, host_impl_->active_tree()->current_page_scale_factor()); + EXPECT_EQ(2, host_impl_->active_tree() + ->property_trees() + ->transform_tree() + .page_scale_factor()); TransformNode* pending_tree_node = host_impl_->pending_tree()->PageScaleTransformNode(); - // Before pending tree updates draw properties, its properties are still - // based on 1.0 page scale, except for current_page_scale_factor() which is a - // shared data between the active and pending trees. - EXPECT_TRUE(pending_tree_node->local.IsIdentity()); + + // Since the pending tree shares the scale factor with the active tree, its + // value and property trees should also have been updated. + EXPECT_TRUE(pending_tree_node->local.IsScale2d()); + EXPECT_EQ(gfx::Vector2dF(2, 2), pending_tree_node->local.To2dScale()); EXPECT_EQ(gfx::Point3F(), pending_tree_node->origin); EXPECT_EQ(2, host_impl_->pending_tree()->current_page_scale_factor()); - EXPECT_EQ(1, host_impl_->pending_tree() + EXPECT_EQ(2, host_impl_->pending_tree() ->property_trees() ->transform_tree() .page_scale_factor()); + // Update draw properties doesn't change the correct values host_impl_->pending_tree()->set_needs_update_draw_properties(); UpdateDrawProperties(host_impl_->pending_tree()); pending_tree_node = host_impl_->pending_tree()->PageScaleTransformNode(); @@ -16168,7 +16176,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, CheckerImagingTileInvalidation) { host_impl_->WillBeginImplFrame(begin_frame_args); // Create the pending tree. - host_impl_->BeginCommit(0); + host_impl_->BeginCommit(0, /*trace_id=*/1); LayerTreeImpl* pending_tree = host_impl_->pending_tree(); auto* root = SetupRootLayer<FakePictureLayerImpl>(pending_tree, layer_size, raster_source); @@ -16303,7 +16311,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, RasterColorSpaceHDR) { EXPECT_EQ(wcg_params.sdr_max_luminance_nits, kCustomWhiteLevel); EXPECT_EQ(wcg_params.hdr_max_luminance_relative, 1.f); - EXPECT_EQ(hdr_params.color_space, hdr); + EXPECT_EQ(hdr_params.color_space, gfx::ColorSpace::CreateExtendedSRGB()); EXPECT_EQ(hdr_params.sdr_max_luminance_nits, kCustomWhiteLevel); EXPECT_EQ(hdr_params.hdr_max_luminance_relative, kHDRMaxLuminanceRelative); } @@ -18295,4 +18303,62 @@ TEST_F(LayerTreeHostImplTest, CollectRegionCaptureBounds) { collected_bounds.bounds().find(kFourthId)->second); } +// Check if picturelayer's ScrollInteractionInProgress() return true even when +// BrowserControl is consuming ScrollUpdate. +TEST_P(LayerTreeHostImplBrowserControlsTest, + BrowserControlsScrollInteractionInProgress) { + gfx::Size inner_size = gfx::Size(100, 100); + gfx::Size outer_size = gfx::Size(100, 100); + gfx::Size content_size = gfx::Size(100, 200); + SetupBrowserControlsAndScrollLayerWithVirtualViewport(inner_size, outer_size, + content_size); + + LayerTreeImpl* active_tree = host_impl_->active_tree(); + + // Create a content layer beneath the outer viewport scroll layer. + scoped_refptr<FakeRasterSource> raster_source( + FakeRasterSource::CreateFilled(content_size)); + + auto* picture_layer = + AddLayer<FakePictureLayerImpl>(host_impl_->active_tree(), raster_source); + CopyProperties(OuterViewportScrollLayer(), picture_layer); + picture_layer->SetBounds(content_size); + picture_layer->SetDrawsContent(true); + picture_layer->SetNeedsPushProperties(); + active_tree->PushPageScaleFromMainThread(1.0f, 1.0f, 2.0f); + DrawFrame(); + + EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, + GetInputHandler() + .ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 50), + ui::ScrollInputType::kTouchscreen) + .get(), + ui::ScrollInputType::kTouchscreen) + .thread); + // shownratio == 1 + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); + EXPECT_EQ(picture_layer->ScrollInteractionInProgress(), false); + + // 0 < shownratio <1 + GetInputHandler().ScrollUpdate(UpdateState(gfx::Point(), + gfx::Vector2dF(0, 25), + ui::ScrollInputType::kTouchscreen) + .get()); + EXPECT_GT(host_impl_->active_tree()->CurrentTopControlsShownRatio(), 0); + EXPECT_LT(host_impl_->active_tree()->CurrentTopControlsShownRatio(), 1); + EXPECT_EQ(picture_layer->ScrollInteractionInProgress(), true); + + GetInputHandler().ScrollUpdate(UpdateState(gfx::Point(), + gfx::Vector2dF(0, 30), + ui::ScrollInputType::kTouchscreen) + .get()); + // now shownratio == 0 + EXPECT_EQ(0, host_impl_->active_tree()->CurrentTopControlsShownRatio()); + EXPECT_EQ(picture_layer->ScrollInteractionInProgress(), true); + + GetInputHandler().ScrollEnd(); + // scroll end, shownratio == 0 + EXPECT_EQ(0, host_impl_->active_tree()->CurrentTopControlsShownRatio()); + EXPECT_EQ(picture_layer->ScrollInteractionInProgress(), false); +} } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc index f8b31c672ca..fc3d5a9f063 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc @@ -63,7 +63,6 @@ using RenderPassOptions = uint32_t; const uint32_t kUseMasks = 1 << 0; const uint32_t kUseAntialiasing = 1 << 1; const uint32_t kUseColorMatrix = 1 << 2; -const uint32_t kForceShaders = 1 << 3; class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest, @@ -72,8 +71,7 @@ class LayerTreeHostBlendingPixelTest public: LayerTreeHostBlendingPixelTest() : LayerTreeHostPixelResourceTest(resource_type()), - force_antialiasing_(false), - force_blending_with_shaders_(false) { + force_antialiasing_(false) { pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true); } @@ -93,8 +91,6 @@ class LayerTreeHostBlendingPixelTest override { viz::RendererSettings modified_renderer_settings = renderer_settings; modified_renderer_settings.force_antialiasing = force_antialiasing_; - modified_renderer_settings.force_blending_with_shaders = - force_blending_with_shaders_; return LayerTreeHostPixelResourceTest::CreateLayerTreeFrameSink( modified_renderer_settings, refresh_rate, compositor_context_provider, worker_context_provider); @@ -211,10 +207,6 @@ class LayerTreeHostBlendingPixelTest const int kRootWidth = 2; const int kRootHeight = kRootWidth * kCSSTestColorsCount; - // Force shaders only applies to gl renderer. - if (renderer_type_ != viz::RendererType::kGL && flags & kForceShaders) - return; - SCOPED_TRACE(TestTypeToString()); SCOPED_TRACE(SkBlendMode_Name(current_blend_mode())); @@ -229,10 +221,8 @@ class LayerTreeHostBlendingPixelTest CreateBlendingColorLayers(kRootWidth, kRootHeight, background.get(), flags); force_antialiasing_ = (flags & kUseAntialiasing); - force_blending_with_shaders_ = (flags & kForceShaders); - if ((renderer_type_ == viz::RendererType::kGL && force_antialiasing_) || - renderer_type_ == viz::RendererType::kSkiaVk) { + if (renderer_type_ == viz::RendererType::kSkiaVk) { // Blending results might differ with one pixel. float percentage_pixels_error = 35.f; float percentage_pixels_small_error = 0.f; @@ -252,7 +242,6 @@ class LayerTreeHostBlendingPixelTest } bool force_antialiasing_; - bool force_blending_with_shaders_; FakeContentLayerClient mask_client_; FakeContentLayerClient backdrop_client_; SkColor misc_opaque_color_ = 0xffc86464; @@ -261,9 +250,6 @@ class LayerTreeHostBlendingPixelTest std::vector<RasterTestConfig> const kTestCases = { {viz::RendererType::kSoftware, TestRasterType::kBitmap}, #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - {viz::RendererType::kGL, TestRasterType::kZeroCopy}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) {viz::RendererType::kSkiaGL, TestRasterType::kGpu}, #endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS) #if BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS) @@ -423,44 +409,6 @@ TEST_P(LayerTreeHostBlendingPixelTest, RunBlendingWithRenderPass(kUseMasks | kUseAntialiasing | kUseColorMatrix); } -TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShaders) { - RunBlendingWithRenderPass(kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersAA) { - RunBlendingWithRenderPass(kUseAntialiasing | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersWithMask) { - RunBlendingWithRenderPass(kUseMasks | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, - BlendingWithRenderPassShadersWithMaskAA) { - RunBlendingWithRenderPass(kUseMasks | kUseAntialiasing | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, - BlendingWithRenderPassShadersColorMatrix) { - RunBlendingWithRenderPass(kUseColorMatrix | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, - BlendingWithRenderPassShadersColorMatrixAA) { - RunBlendingWithRenderPass(kUseAntialiasing | kUseColorMatrix | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, - BlendingWithRenderPassShadersWithMaskColorMatrix) { - RunBlendingWithRenderPass(kUseMasks | kUseColorMatrix | kForceShaders); -} - -TEST_P(LayerTreeHostBlendingPixelTest, - BlendingWithRenderPassShadersWithMaskColorMatrixAA) { - RunBlendingWithRenderPass(kUseMasks | kUseAntialiasing | kUseColorMatrix | - kForceShaders); -} - } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index 40114681266..e4b55f0fee0 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -32,8 +32,6 @@ class LayerTreeHostFiltersPixelTest // generating separate base line file paths. const char* GetRendererSuffix() { switch (renderer_type_) { - case viz::RendererType::kGL: - return "gl"; case viz::RendererType::kSkiaGL: return "skia_gl"; case viz::RendererType::kSkiaVk: @@ -151,12 +149,9 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterInvalid) { } TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRadius) { -#if BUILDFLAG(IS_FUCHSIA) - // TODO(crbug.com/1311459): This test case fails on SwiftShader FEMU due - // to a new implementation of log/exp functions in SwiftShader. We should - // re-enable the test case once the bug is fixed. +#if defined(MEMORY_SANITIZER) if (renderer_type() == viz::RendererType::kSkiaVk) { - GTEST_SKIP(); + GTEST_SKIP() << "TODO(crbug.com/1324336): Uninitialized data error"; } #endif if (use_software_renderer()) { @@ -180,7 +175,9 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRadius) { gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0); blur->SetBackdropFilterBounds(backdrop_filter_bounds); -#if BUILDFLAG(IS_WIN) || defined(ARCH_CPU_ARM64) +#if BUILDFLAG(IS_FUCHSIA) + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); +#elif BUILDFLAG(IS_WIN) || defined(ARCH_CPU_ARM64) // Windows and ARM64 have 436 pixels off by 1: crbug.com/259915 float percentage_pixels_large_error = 1.09f; // 436px / (200*200) float percentage_pixels_small_error = 0.0f; @@ -249,6 +246,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) { } TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) { +#if defined(MEMORY_SANITIZER) + if (renderer_type() == viz::RendererType::kSkiaVk) { + GTEST_SKIP() << "TODO(crbug.com/1324336): Uninitialized data error"; + } +#endif scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); @@ -553,14 +555,6 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterClipped) { } TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) { -#if BUILDFLAG(IS_FUCHSIA) - // TODO(crbug.com/1311459): This test case fails on SwiftShader FEMU due - // to a new implementation of log/exp functions in SwiftShader. We should - // re-enable the test case once the bug is fixed. - if (renderer_type() == viz::RendererType::kSkiaVk) { - GTEST_SKIP(); - } -#endif scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); @@ -599,7 +593,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) { filter->SetBackdropFilters(filters); filter->ClearBackdropFilterBounds(); -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) || \ +#if BUILDFLAG(IS_FUCHSIA) + if (renderer_type() == viz::RendererType::kSkiaVk) { + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); + } +#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) || \ defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if BUILDFLAG(IS_WIN) // Windows has 153 pixels off by at most 2: crbug.com/225027 diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc index 6666f037039..c6bb12f88f5 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc @@ -31,11 +31,6 @@ namespace { std::vector<RasterTestConfig> const kTestCases = { {viz::RendererType::kSoftware, TestRasterType::kBitmap}, #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - {viz::RendererType::kGL, TestRasterType::kGpu}, - {viz::RendererType::kGL, TestRasterType::kOneCopy}, - {viz::RendererType::kGL, TestRasterType::kZeroCopy}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) {viz::RendererType::kSkiaGL, TestRasterType::kGpu}, {viz::RendererType::kSkiaGL, TestRasterType::kOneCopy}, {viz::RendererType::kSkiaGL, TestRasterType::kZeroCopy}, @@ -69,13 +64,13 @@ class MaskContentLayerClient : public ContentLayerClient { display_list->push<SaveOp>(); display_list->push<ClipRectOp>(gfx::RectToSkRect(PaintableRegion()), SkClipOp::kIntersect, false); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; display_list->push<DrawColorOp>(color, SkBlendMode::kSrc); PaintFlags flags; flags.setStyle(PaintFlags::kStroke_Style); flags.setStrokeWidth(SkIntToScalar(2)); - flags.setColor(SK_ColorWHITE); + flags.setColor(SkColors::kWhite); gfx::Rect inset_rect(bounds_); while (!inset_rect.IsEmpty()) { @@ -259,7 +254,7 @@ class LayerTreeHostMaskPixelTest_MaskWithEffectNoContentToMask LayerList layers = layer_tree_host()->root_layer()->children(); DCHECK_EQ(3u, layers.size()); // Set background to red. - layers[0]->SetBackgroundColor(SK_ColorRED); + layers[0]->SetBackgroundColor(SkColors::kRed); // Remove the green layer. layers.erase(layers.begin() + 1); layer_tree_host()->root_layer()->SetChildLayerList(layers); @@ -449,7 +444,7 @@ class CheckerContentLayerClient : public ContentLayerClient { display_list->push<SaveOp>(); display_list->push<ClipRectOp>(gfx::RectToSkRect(PaintableRegion()), SkClipOp::kIntersect, false); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; display_list->push<DrawColorOp>(color, SkBlendMode::kSrc); PaintFlags flags; @@ -496,7 +491,7 @@ class CircleContentLayerClient : public ContentLayerClient { display_list->push<SaveOp>(); display_list->push<ClipRectOp>(gfx::RectToSkRect(PaintableRegion()), SkClipOp::kIntersect, false); - SkColor color = SK_ColorTRANSPARENT; + SkColor4f color = SkColors::kTransparent; display_list->push<DrawColorOp>(color, SkBlendMode::kSrc); PaintFlags flags; @@ -788,8 +783,10 @@ class LayerTreeHostMaskAsBlendingPixelTest static scoped_refptr<Layer> CreateCheckerboardLayer(const gfx::Size& bounds) { constexpr int kGridSize = 8; - static const SkColor color_even = SkColorSetRGB(153, 153, 153); - static const SkColor color_odd = SkColorSetRGB(102, 102, 102); + static const SkColor4f color_even = + SkColor4f::FromColor(SkColorSetRGB(153, 153, 153)); + static const SkColor4f color_odd = + SkColor4f::FromColor(SkColorSetRGB(102, 102, 102)); auto display_list = base::MakeRefCounted<DisplayItemList>(); display_list->StartPaint(); @@ -873,15 +870,6 @@ class LayerTreeHostMaskAsBlendingPixelTest MaskTestConfig const kTestConfigs[] = { MaskTestConfig{{viz::RendererType::kSoftware, TestRasterType::kBitmap}, 0}, #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - MaskTestConfig{{viz::RendererType::kGL, TestRasterType::kZeroCopy}, 0}, - MaskTestConfig{{viz::RendererType::kGL, TestRasterType::kZeroCopy}, - kUseAntialiasing}, - MaskTestConfig{{viz::RendererType::kGL, TestRasterType::kZeroCopy}, - kForceShaders}, - MaskTestConfig{{viz::RendererType::kGL, TestRasterType::kZeroCopy}, - kUseAntialiasing | kForceShaders}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) MaskTestConfig{{viz::RendererType::kSkiaGL, TestRasterType::kZeroCopy}, 0}, MaskTestConfig{{viz::RendererType::kSkiaGL, TestRasterType::kZeroCopy}, kUseAntialiasing}, diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc index 873f6469fc5..12d20437f73 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc @@ -441,10 +441,6 @@ TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) { ReadbackTestConfig const kTestConfigs[] = { ReadbackTestConfig{viz::RendererType::kSoftware, TestReadBackType::kBitmap}, #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - ReadbackTestConfig{viz::RendererType::kGL, TestReadBackType::kTexture}, - ReadbackTestConfig{viz::RendererType::kGL, TestReadBackType::kBitmap}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) ReadbackTestConfig{viz::RendererType::kSkiaGL, TestReadBackType::kTexture}, ReadbackTestConfig{viz::RendererType::kSkiaGL, TestReadBackType::kBitmap}, #endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS) diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc index 76fc847c36a..fa8d72496d7 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc @@ -12,6 +12,7 @@ #include "cc/paint/paint_flags.h" #include "cc/paint/paint_op_buffer.h" #include "cc/test/layer_tree_pixel_test.h" +#include "cc/test/pixel_comparator.h" #include "cc/test/test_layer_tree_frame_sink.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/test/buildflags.h" @@ -222,10 +223,6 @@ class LayerTreeHostTilesTestRasterColorSpace std::vector<RasterTestConfig> const kTestCases = { {viz::RendererType::kSoftware, TestRasterType::kBitmap}, #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - {viz::RendererType::kGL, TestRasterType::kOneCopy}, - {viz::RendererType::kGL, TestRasterType::kGpu}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) {viz::RendererType::kSkiaGL, TestRasterType::kOneCopy}, {viz::RendererType::kSkiaGL, TestRasterType::kGpu}, #endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS) @@ -265,9 +262,6 @@ TEST_P(LayerTreeHostTilesTestPartialInvalidation, FullRaster) { std::vector<RasterTestConfig> const kTestCasesMultiThread = { #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS) -#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS) - {viz::RendererType::kGL, TestRasterType::kOneCopy}, -#endif // BUILDFLAG(ENABLE_GL_RENDERER_TESTS) {viz::RendererType::kSkiaGL, TestRasterType::kOneCopy}, #endif // BUILDFLAG(ENABLE_GL_BACKEND_TESTS) #if BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS) @@ -335,11 +329,18 @@ TEST_P(LayerTreeHostTilesTestRasterColorSpace, GenericRGB) { SetColorSpace(gfx::ColorSpace(gfx::ColorSpace::PrimaryID::APPLE_GENERIC_RGB, gfx::ColorSpace::TransferID::GAMMA18)); - RunPixelTest(picture_layer_, - base::FilePath(FILE_PATH_LITERAL("primary_colors.png"))); + // Software rasterizer ignores XYZD50 matrix + const auto* target_png = + renderer_type() == viz::RendererType::kSoftware + ? FILE_PATH_LITERAL("primary_colors.png") + : FILE_PATH_LITERAL("primary_colors_sRGB_in_AdobeRGB.png"); + RunPixelTest(picture_layer_, base::FilePath(target_png)); } TEST_P(LayerTreeHostTilesTestRasterColorSpace, CustomColorSpace) { +#if BUILDFLAG(IS_FUCHSIA) + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); +#endif // Create a color space with a different blue point. SkColorSpacePrimaries primaries; skcms_Matrix3x3 to_XYZD50; @@ -355,8 +356,11 @@ TEST_P(LayerTreeHostTilesTestRasterColorSpace, CustomColorSpace) { SetColorSpace(gfx::ColorSpace::CreateCustom( to_XYZD50, gfx::ColorSpace::TransferID::SRGB)); - RunPixelTest(picture_layer_, - base::FilePath(FILE_PATH_LITERAL("primary_colors.png"))); + // Software rasterizer ignores XYZD50 matrix + const auto* target_png = renderer_type() == viz::RendererType::kSoftware + ? FILE_PATH_LITERAL("primary_colors.png") + : FILE_PATH_LITERAL("primary_colors_icced.png"); + RunPixelTest(picture_layer_, base::FilePath(target_png)); } // This test doesn't work on Vulkan because on our hardware we can't render to diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index a2c426e4e93..c66f51e04c6 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -79,6 +79,7 @@ #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/service/display/output_surface.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/test_gles2_interface.h" @@ -109,10 +110,6 @@ using testing::StrictMock; namespace cc { namespace { -const char kUserInteraction[] = "Compositor.UserInteraction"; -const char kCheckerboardArea[] = "CheckerboardedContentArea"; -const char kCheckerboardAreaRatio[] = "CheckerboardedContentAreaRatio"; -const char kMissingTiles[] = "NumMissingTiles"; bool LayerSubtreeHasCopyRequest(Layer* layer) { const LayerTreeHost* host = layer->layer_tree_host(); @@ -315,15 +312,12 @@ class LayerTreeHostTestSchedulingClient : public LayerTreeHostTest { public: void BeginTest() override { PostSetNeedsCommitToMainThread(); - EXPECT_EQ(0, main_frame_scheduled_count_); EXPECT_EQ(0, main_frame_run_count_); } - void DidScheduleBeginMainFrame() override { main_frame_scheduled_count_++; } void DidRunBeginMainFrame() override { main_frame_run_count_++; } void DidBeginMainFrame() override { - EXPECT_EQ(1, main_frame_scheduled_count_); EXPECT_EQ(1, main_frame_run_count_); EndTest(); } @@ -331,7 +325,6 @@ class LayerTreeHostTestSchedulingClient : public LayerTreeHostTest { void AfterTest() override {} private: - int main_frame_scheduled_count_ = 0; int main_frame_run_count_ = 0; }; @@ -7391,30 +7384,6 @@ class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest { // thread. MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEnds); -class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy - : public LayerTreeHostTestCrispUpAfterPinchEnds { - protected: - std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( - scoped_refptr<viz::ContextProvider> compositor_context_provider) - override { - scoped_refptr<viz::TestContextProvider> display_context_provider = - viz::TestContextProvider::Create(); - viz::TestGLES2Interface* gl = - display_context_provider->UnboundTestContextGL(); - gl->set_support_sync_query(true); -#if BUILDFLAG(IS_MAC) - gl->set_support_texture_rectangle(true); -#endif - display_context_provider->BindToCurrentThread(); - return LayerTreeTest::CreateDisplayOutputSurfaceOnThread( - std::move(display_context_provider)); - } -}; - -// This test does pinching on the impl side which is not supported in single -// thread. -MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy); - class RasterizeWithGpuRasterizationCreatesResources : public LayerTreeHostTest { protected: void SetUpUnboundContextProviders( @@ -8534,7 +8503,7 @@ class LayerTreeHostTestDiscardAckAfterRelease : public LayerTreeHostTest { // LayerTreeFrameSink was not released. We must receive the ack. EXPECT_TRUE(received_ack_); // Cause damage so that we draw and swap. - layer_tree_host()->root_layer()->SetBackgroundColor(SK_ColorGREEN); + layer_tree_host()->root_layer()->SetBackgroundColor(SkColors::kGreen); break; case 2: // LayerTreeFrameSink was released. The ack must be discarded. @@ -8782,74 +8751,6 @@ class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest { MULTI_THREAD_TEST_F(LayerTreeHostTestImageDecodingHints); -class LayerTreeHostTestCheckerboardUkm : public LayerTreeHostTest { - public: - LayerTreeHostTestCheckerboardUkm() : url_(GURL("https://example.com")), - ukm_source_id_(123) {} - void BeginTest() override { - PostSetNeedsCommitToMainThread(); - layer_tree_host()->SetSourceURL(ukm_source_id_, url_); - } - - void SetupTree() override { - gfx::Size layer_size(100, 100); - content_layer_client_.set_bounds(layer_size); - content_layer_client_.set_fill_with_nonsolid_color(true); - layer_tree_host()->SetRootLayer( - FakePictureLayer::Create(&content_layer_client_)); - layer_tree_host()->root_layer()->SetBounds(layer_size); - LayerTreeTest::SetupTree(); - } - - void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { - if (impl->active_tree()->source_frame_number() != 0) - return; - - // We have an active tree. Start a pinch gesture so we start recording - // stats. - impl->GetInputHandler().PinchGestureBegin( - gfx::Point(100, 100), ui::ScrollInputType::kTouchscreen); - } - - void DrawLayersOnThread(LayerTreeHostImpl* impl) override { - if (!impl->GetInputHandler().pinch_gesture_active()) - return; - - // We just drew a frame, stats for it should have been recorded. End the - // gesture so they are flushed to the recorder. - impl->GetInputHandler().PinchGestureEnd(gfx::Point(50, 50)); - - // RenewTreePriority will run when the smoothness expiration timer fires. - // Synthetically do it here so the UkmManager is notified. - impl->RenewTreePriorityForTesting(); - - 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()); - for (const auto* entry : entries) { - recorder->ExpectEntrySourceHasUrl(entry, url_); - recorder->ExpectEntryMetric(entry, kCheckerboardArea, 0); - recorder->ExpectEntryMetric(entry, kMissingTiles, 0); - recorder->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 0); - } - - EndTest(); - } - - private: - const GURL url_; - const ukm::SourceId ukm_source_id_; - FakeContentLayerClient content_layer_client_; -}; - -// Only multi-thread mode needs to record UKMs. -MULTI_THREAD_TEST_F(LayerTreeHostTestCheckerboardUkm); - class DontUpdateLayersWithEmptyBounds : public LayerTreeTest { protected: void SetupTree() override { @@ -10122,7 +10023,7 @@ class LayerTreeHostTestOccludedTileReleased void AddLayerThatObscuresPictureLayer() { auto covering_layer = SolidColorLayer::Create(); covering_layer->SetBounds(gfx::Size(100, 100)); - covering_layer->SetBackgroundColor(SK_ColorRED); + covering_layer->SetBackgroundColor(SkColors::kRed); covering_layer->SetIsDrawable(true); layer_tree_host()->root_layer()->AddChild(covering_layer); added_obscuring_layer_ = true; @@ -10146,5 +10047,292 @@ class LayerTreeHostTestNoCommitDeadlock : public LayerTreeHostTest { }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoCommitDeadlock); + +// In real site, problem happened like this +// 1. commit +// 2. tiling is delayed, so NotifyReadyToActivate is not triggered +// 3. Draw is called and NotifyReadyToActivate is triggered +// during PrepareDraw() by TileManager's CheckForCompletedTask(). +// 4. pending_tree()::UpdateDrawProperties() is called after PrepareDraw(), +// and tiling is recreated if transform is changed +// 5. Activation happen right after the Draw +// So tiling with empty tiles will be activated to active tree. +class LayerTreeHostTestDelayRecreateTiling + : public LayerTreeHostTestWithHelper { + public: + LayerTreeHostTestDelayRecreateTiling() {} + + void SetupTree() override { + client_.set_fill_with_nonsolid_color(true); + scoped_refptr<FakePictureLayer> root_layer = + FakePictureLayer::Create(&client_); + root_layer->SetBounds(gfx::Size(150, 150)); + root_layer->SetIsDrawable(true); + + layer_on_main_ = + CreateAndAddFakePictureLayer(gfx::Size(30, 30), root_layer.get()); + + // initial transform to force transform node + gfx::Transform transform; + transform.Scale(2.0f, 1.0f); + layer_on_main_->SetTransform(transform); + + layer_tree_host()->SetRootLayer(root_layer); + + LayerTreeHostTest::SetupTree(); + client_.set_bounds(root_layer->bounds()); + + layer_id_ = layer_on_main_->id(); + } + + void WillCommit(const CommitState&) override { + TransformTree& transform_tree = + layer_tree_host()->property_trees()->transform_tree_mutable(); + TransformNode* node = + transform_tree.Node(layer_on_main_->transform_tree_index()); + + gfx::Transform transform; + transform.Scale(2.0f, 1.0f); + transform.Translate(0.0f, 0.8f); + + switch (layer_tree_host()->SourceFrameNumber()) { + case 1: + // in frame1, translation changed and animation start + transform_tree.OnTransformAnimated(layer_on_main_->element_id(), + transform); + node->has_potential_animation = true; + break; + } + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + FakePictureLayerImpl* layer_impl = static_cast<FakePictureLayerImpl*>( + host_impl->pending_tree()->LayerById(layer_id_)); + + TransformTree& transform_tree = + host_impl->pending_tree()->property_trees()->transform_tree_mutable(); + TransformNode* node = + transform_tree.Node(layer_impl->transform_tree_index()); + + if (host_impl->pending_tree()->source_frame_number() == 2) { + // delay Activation for this pending tree + host_impl->BlockNotifyReadyToActivateForTesting(true); + + // to reproduce problem, conditions to recreate tiling should be changed + // after commitcomplete + // e.g., transform change, animation status change + // commitcomplete -> beginimpl -> draw (pending's updatedrawproperties) + // in beginimpl, scroll can be handled, so transform can be changed + // in draw, UpdateAnimationState can change animation status + node->has_potential_animation = false; + transform_tree.set_needs_update(true); + host_impl->pending_tree()->set_needs_update_draw_properties(); + + // to make sure Draw happen + host_impl->SetNeedsRedraw(); + } + } + + DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + DrawResult draw_result) override { + if (host_impl->pending_tree() && + host_impl->pending_tree()->source_frame_number() == 2) { + host_impl->BlockNotifyReadyToActivateForTesting(false, false); + // BlockNotifyReadyToActivateForTesting(false) call NotifyReadyToActivate, + // but NotifyReadyToActivate should be called directly instead of PostTask + // because it should called inside PrepareToDraw() + host_impl->NotifyReadyToActivate(); + } + return draw_result; + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + FakePictureLayerImpl* layer_impl = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->LayerById(layer_id_)); + + gfx::AxisTransform2d tiling_transform = + layer_impl->HighResTiling()->raster_transform(); + + switch (host_impl->active_tree()->source_frame_number()) { + case 0: + PostSetNeedsCommitToMainThread(); + break; + case 1: + PostSetNeedsCommitToMainThread(); + break; + case 2: + if (should_delay_recreating_tiling_) { + // translation is changed in frame2, but recreating tiling should not + // happen because ReadyToActivate is true + ASSERT_EQ(tiling_transform.scale(), gfx::Vector2dF(2.0f, 1.0f)); + ASSERT_EQ(tiling_transform.translation(), gfx::Vector2dF(0, 0)); + should_delay_recreating_tiling_ = false; + } else { + // Invalidating implside will trigger recreating tiling without next + // commit + ASSERT_EQ(tiling_transform.scale(), gfx::Vector2dF(2.0f, 1.0f)); + ASSERT_EQ(tiling_transform.translation(), gfx::Vector2dF(0, 0.8f)); + EndTest(); + } + break; + case 3: + NOTREACHED() << "We shouldn't see another commit in this test"; + break; + } + } + + protected: + FakeContentLayerClient client_; + // to access layer information in main and impl + int layer_id_; + // to access layer information in main's WillCommit() + scoped_refptr<FakePictureLayer> layer_on_main_; + bool should_delay_recreating_tiling_ = true; +}; +MULTI_THREAD_TEST_F(LayerTreeHostTestDelayRecreateTiling); + +// This test validate that recreating tiling is delayed by veto conditions and +// the delayed tiling is created again when the veto conditions are reset. +class LayerTreeHostTestInvalidateImplSideForRerasterTiling + : public LayerTreeHostTestWithHelper { + public: + void SetupTree() override { + client_.set_fill_with_nonsolid_color(true); + scoped_refptr<FakePictureLayer> root_layer = + FakePictureLayer::Create(&client_); + root_layer->SetBounds(gfx::Size(150, 150)); + root_layer->SetIsDrawable(true); + + layer_on_main_ = + CreateAndAddFakePictureLayer(gfx::Size(30, 30), root_layer.get()); + + // initial transform to force transform node + gfx::Transform transform; + transform.Scale(2.0f, 1.0f); + layer_on_main_->SetTransform(transform); + + layer_tree_host()->SetRootLayer(root_layer); + + LayerTreeHostTest::SetupTree(); + client_.set_bounds(root_layer->bounds()); + + layer_id_ = layer_on_main_->id(); + } + + void WillCommit(const CommitState&) override { + TransformTree& transform_tree = + layer_tree_host()->property_trees()->transform_tree_mutable(); + TransformNode* node = + transform_tree.Node(layer_on_main_->transform_tree_index()); + + gfx::Transform transform; + transform.Scale(2.0f, 1.0f); + transform.Translate(0.0f, 0.8f); + + switch (layer_tree_host()->SourceFrameNumber()) { + case 1: + // in frame1, translation changed and animation start + transform_tree.OnTransformAnimated(layer_on_main_->element_id(), + transform); + node->has_potential_animation = true; + break; + } + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void ClearAnimationForLayer(LayerTreeImpl* tree_impl, + FakePictureLayerImpl* layer_impl) { + if (!tree_impl) + return; + + TransformTree& transform_tree = + tree_impl->property_trees()->transform_tree_mutable(); + TransformNode* node = + transform_tree.Node(layer_impl->transform_tree_index()); + + node->has_potential_animation = false; + transform_tree.set_needs_update(true); + tree_impl->set_needs_update_draw_properties(); + } + + TransformNode* TransformNodeForLayer(LayerTreeImpl* tree_impl, + FakePictureLayerImpl* layer_impl) { + TransformTree& transform_tree = + tree_impl->property_trees()->transform_tree_mutable(); + TransformNode* node = + transform_tree.Node(layer_impl->transform_tree_index()); + return node; + } + + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->active_tree()->source_frame_number() == 2) { + FakePictureLayerImpl* target_layer = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->LayerById(layer_id_)); + gfx::AxisTransform2d tiling_transform = + target_layer->HighResTiling()->raster_transform(); + TransformNode* node = + TransformNodeForLayer(host_impl->active_tree(), target_layer); + if (node->has_potential_animation) { + // in frame 2, active tree still have old tiling because animation is + // still active. + EXPECT_EQ(tiling_transform.scale(), gfx::Vector2dF(2.0f, 1.0f)); + EXPECT_EQ(tiling_transform.translation(), gfx::Vector2dF(0, 0)); + + // now clear animation and trigger a new draw to check if invalidation + // implside will be requested for rerastering tiling. + ClearAnimationForLayer(host_impl->active_tree(), target_layer); + ClearAnimationForLayer(host_impl->recycle_tree(), target_layer); + host_impl->SetNeedsRedraw(); + } + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + FakePictureLayerImpl* target_layer = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->LayerById(layer_id_)); + gfx::AxisTransform2d tiling_transform = + target_layer->HighResTiling()->raster_transform(); + TransformNode* node = + TransformNodeForLayer(host_impl->active_tree(), target_layer); + switch (host_impl->active_tree()->source_frame_number()) { + case 0: + PostSetNeedsCommitToMainThread(); + break; + case 1: + PostSetNeedsCommitToMainThread(); + break; + case 2: + if (node->has_potential_animation) { + // translation is changed in frame2, but recreating tiling should not + // happen because animation is still active. + EXPECT_EQ(tiling_transform.scale(), gfx::Vector2dF(2.0f, 1.0f)); + EXPECT_EQ(tiling_transform.translation(), gfx::Vector2dF(0, 0)); + + // trigger draw to check if invalidating implside is not triggered + // if animation is still active. + host_impl->SetNeedsRedraw(); + } else { + // check if invalidation implside was requested successfully. + // new tiling should be created. + EXPECT_EQ(tiling_transform.scale(), gfx::Vector2dF(2.0f, 1.0f)); + EXPECT_EQ(tiling_transform.translation(), gfx::Vector2dF(0, 0.8f)); + EndTest(); + } + break; + } + } + + protected: + FakeContentLayerClient client_; + // to access layer information in main and impl + int layer_id_; + // to access layer information in main's WillCommit() + scoped_refptr<FakePictureLayer> layer_on_main_; +}; +MULTI_THREAD_TEST_F(LayerTreeHostTestInvalidateImplSideForRerasterTiling); } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc index 0a61548c68a..8dd6266cc57 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc @@ -60,6 +60,14 @@ class LayerTreeHostAnimationTest : public LayerTreeTest { timeline_->AttachAnimation(animation_child_.get()); } + void DetachAnimationsFromTimeline() { + if (animation_) + timeline_->DetachAnimation(animation_.get()); + if (animation_child_) + timeline_->DetachAnimation(animation_child_.get()); + animation_host()->RemoveAnimationTimeline(timeline_.get()); + } + void GetImplTimelineAndAnimationByID(const LayerTreeHostImpl& host_impl) { AnimationHost* animation_host_impl = GetImplAnimationHost(&host_impl); timeline_impl_ = animation_host_impl->GetTimelineById(timeline_id_); @@ -71,6 +79,14 @@ class LayerTreeHostAnimationTest : public LayerTreeTest { EXPECT_TRUE(animation_child_impl_); } + void CleanupBeforeDestroy() override { + // This needs to happen on the main thread (so can't happen in + // EndTest()), and needs to happen before DestroyLayerTreeHost() + // (which will trigger assertions if we don't do this), so it can't + // happen in AfterTest(). + DetachAnimationsFromTimeline(); + } + AnimationHost* GetImplAnimationHost( const LayerTreeHostImpl* host_impl) const { return static_cast<AnimationHost*>(host_impl->mutator_host()); @@ -902,10 +918,8 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted scroll_layer_element_id_ = scroll_layer_->element_id(); } - KeyframeEffect& ScrollOffsetKeyframeEffect( - const LayerTreeHostImpl& host_impl, - scoped_refptr<FakePictureLayer> layer, - ElementId element_id) const { + KeyframeEffect& ScrollOffsetKeyframeEffect(const LayerTreeHostImpl& host_impl, + ElementId element_id) const { scoped_refptr<ElementAnimations> element_animations = GetImplAnimationHost(&host_impl) ->GetElementAnimationsForElementId(element_id); @@ -941,8 +955,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted // This happens after the impl-only animation is added in // WillCommitCompleteOnThread. gfx::KeyframeModel* keyframe_model = - ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_, - scroll_layer_element_id_) + ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_element_id_) .GetKeyframeModel(TargetProperty::SCROLL_OFFSET); DCHECK(keyframe_model); const ScrollOffsetAnimationCurve* curve = @@ -969,8 +982,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { if (host_impl->sync_tree()->source_frame_number() == 2) { gfx::KeyframeModel* keyframe_model = - ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_, - scroll_layer_element_id_) + ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_element_id_) .GetKeyframeModel(TargetProperty::SCROLL_OFFSET); DCHECK(keyframe_model); const ScrollOffsetAnimationCurve* curve = diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc index 6c47500d499..838e0a4b151 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc @@ -15,8 +15,6 @@ namespace cc { namespace { -const char kRenderingEvent[] = "Compositor.Rendering"; -const char kCheckerboardImagesMetric[] = "CheckerboardedImagesCount"; class LayerTreeHostCheckerImagingTest : public LayerTreeTest { public: @@ -29,26 +27,6 @@ class LayerTreeHostCheckerImagingTest : public LayerTreeTest { PostSetNeedsCommitToMainThread(); } - void VerifyUkmAndEndTest(LayerTreeHostImpl* impl) { - 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. - ukm::SourceId newSourceId = ukm::AssignNewSourceId(); - impl->ukm_manager()->SetSourceId(newSourceId); - recorder->UpdateSourceURL(newSourceId, GURL("chrome://test2")); - - const auto& entries = recorder->GetEntriesByName(kRenderingEvent); - ASSERT_EQ(1u, entries.size()); - auto* entry = entries[0]; - recorder->ExpectEntrySourceHasUrl(entry, url_); - recorder->ExpectEntryMetric(entry, kCheckerboardImagesMetric, 1); - EndTest(); - } - void InitializeSettings(LayerTreeSettings* settings) override { settings->enable_checker_imaging = true; settings->min_image_bytes_to_checker = 512 * 1024; @@ -154,7 +132,7 @@ class LayerTreeHostCheckerImagingTestMergeWithMainFrame expected_update_rect.Union(gfx::Rect(600, 0, 50, 500)); EXPECT_EQ(sync_layer_impl->update_rect(), expected_update_rect); - VerifyUkmAndEndTest(host_impl); + EndTest(); } break; default: NOTREACHED(); @@ -219,7 +197,7 @@ class LayerTreeHostCheckerImagingTestImplSideTree void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { num_of_activations_++; if (num_of_activations_ == 2) { - VerifyUkmAndEndTest(host_impl); + EndTest(); } } diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc index ce695f67d4a..992af86c6d0 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -204,26 +204,12 @@ class LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder return nullptr; } - std::unique_ptr<viz::SkiaOutputSurface> - CreateDisplaySkiaOutputSurfaceOnThread( + std::unique_ptr<viz::SkiaOutputSurface> CreateSkiaOutputSurfaceOnThread( viz::DisplayCompositorMemoryAndTaskController*) override { auto skia_output_surface = viz::FakeSkiaOutputSurface::Create3d(); skia_output_surface->SetOutOfOrderCallbacks(true); return skia_output_surface; } - - 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); - - return viz::FakeOutputSurface::Create3d( - std::move(compositor_context_provider)); - } }; INSTANTIATE_TEST_SUITE_P( @@ -888,25 +874,13 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage // and there is no overlay support. return nullptr; } - std::unique_ptr<viz::SkiaOutputSurface> - CreateDisplaySkiaOutputSurfaceOnThread( + std::unique_ptr<viz::SkiaOutputSurface> CreateSkiaOutputSurfaceOnThread( viz::DisplayCompositorMemoryAndTaskController*) 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 { - // 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 { root_ = FakePictureLayer::Create(&client_); root_->SetBounds(gfx::Size(20, 20)); @@ -1045,25 +1019,13 @@ class LayerTreeHostCopyRequestTestCountSharedImages // and there is no overlay support. return nullptr; } - std::unique_ptr<viz::SkiaOutputSurface> - CreateDisplaySkiaOutputSurfaceOnThread( + std::unique_ptr<viz::SkiaOutputSurface> CreateSkiaOutputSurfaceOnThread( viz::DisplayCompositorMemoryAndTaskController*) 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 { - // 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 { // The layers in this test have solid color content, so they don't // actually allocate any textures, making counting easier. diff --git a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc index 92c066cc2e7..364df3eb933 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc @@ -387,7 +387,7 @@ class LayerTreeHostProxyTestCommitWaitsForActivationMFBA // case above). We unblock activate to allow this main frame to commit. auto unblock = base::BindOnce( &LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting, - base::Unretained(impl), false); + base::Unretained(impl), false, true); // Post the unblock instead of doing it immediately so that the main // frame is fully processed by the compositor thread, and it has a full // opportunity to wrongly unblock the main thread. diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index bb4c9a09d73..13788d94cba 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -166,7 +166,6 @@ LayerTreeImpl::LayerTreeImpl( needs_full_tree_sync_(true), needs_surface_ranges_sync_(false), next_activation_forces_redraw_(false), - has_ever_been_drawn_(false), handle_visibility_changed_(false), have_scroll_event_handlers_(false), event_listener_properties_(), @@ -735,8 +734,6 @@ void LayerTreeImpl::PullLayerTreePropertiesFrom(CommitState& commit_state) { if (commit_state.force_send_metadata_request) RequestForceSendMetadata(); - set_has_ever_been_drawn(false); - // TODO(ericrk): The viewport changes caused by |top_controls_shown_ratio_| // changes should propagate back to the main tree. This does not currently // happen, so we must force the impl tree to update its viewports if @@ -755,6 +752,10 @@ void LayerTreeImpl::PullLayerTreePropertiesFrom(CommitState& commit_state) { // Transfer page transition directives. for (auto& request : commit_state.document_transition_requests) AddDocumentTransitionRequest(std::move(request)); + + SetVisualUpdateDurations( + commit_state.previous_surfaces_visual_update_duration, + commit_state.visual_update_duration); } void LayerTreeImpl::PushPropertyTreesTo(LayerTreeImpl* target_tree) { @@ -844,6 +845,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { // This should match the property synchronization in // LayerTreeHost::finishCommitOnImplThread(). target_tree->set_source_frame_number(source_frame_number()); + target_tree->set_trace_id(trace_id()); target_tree->set_background_color(background_color()); target_tree->set_have_scroll_event_handlers(have_scroll_event_handlers()); target_tree->set_event_listener_properties( @@ -862,8 +864,6 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { else target_tree->set_hud_layer(nullptr); - target_tree->has_ever_been_drawn_ = false; - // Note: this needs to happen after SetPropertyTrees. target_tree->HandleTickmarksVisibilityChange(); target_tree->HandleScrollbarShowRequests(); @@ -881,6 +881,9 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { for (auto& request : TakeDocumentTransitionRequests()) target_tree->AddDocumentTransitionRequest(std::move(request)); + + target_tree->SetVisualUpdateDurations( + previous_surfaces_visual_update_duration_, visual_update_duration_); } void LayerTreeImpl::HandleTickmarksVisibilityChange() { @@ -1153,23 +1156,45 @@ void LayerTreeImpl::UpdateTransformAnimation(ElementId element_id, int transform_node_index) { // This includes all animations, even those that are finished but // haven't yet been deleted. - if (mutator_host()->HasAnyAnimationTargetingProperty( - element_id, TargetProperty::TRANSFORM)) { - TransformTree& transform_tree = property_trees()->transform_tree_mutable(); - if (TransformNode* node = transform_tree.Node(transform_node_index)) { - ElementListType list_type = GetElementTypeForAnimation(); - bool has_potential_animation = - mutator_host()->HasPotentiallyRunningTransformAnimation(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()->MaximumScale(element_id, list_type); - transform_tree.set_needs_update(true); - set_needs_update_draw_properties(); + + // A given ElementId should be associated with only a single transform + // property. However, the ElementId is opaque to cc. (If it comes from + // blink, it was constructed with a CompositorElementIdNamespace specific to + // the correct property. Otherwise, only the transform property should be + // used.) + const TargetProperty::Type transform_properties[] = { + TargetProperty::TRANSFORM, TargetProperty::SCALE, TargetProperty::ROTATE, + TargetProperty::TRANSLATE}; +#if DCHECK_IS_ON() + unsigned property_count = 0u; +#endif + + for (TargetProperty::Type property : transform_properties) { + if (mutator_host()->HasAnyAnimationTargetingProperty(element_id, + property)) { +#if DCHECK_IS_ON() + ++property_count; +#endif + TransformTree& transform_tree = + property_trees()->transform_tree_mutable(); + if (TransformNode* node = transform_tree.Node(transform_node_index)) { + ElementListType list_type = GetElementTypeForAnimation(); + bool has_potential_animation = + mutator_host()->HasPotentiallyRunningAnimationForProperty( + element_id, list_type, property); + if (node->has_potential_animation != has_potential_animation) { + node->has_potential_animation = has_potential_animation; + node->maximum_animation_scale = + mutator_host()->MaximumScale(element_id, list_type); + transform_tree.set_needs_update(true); + set_needs_update_draw_properties(); + } } } } +#if DCHECK_IS_ON() + DCHECK_LE(property_count, 1u); +#endif } void LayerTreeImpl::UpdatePageScaleNode() { @@ -1187,7 +1212,7 @@ void LayerTreeImpl::SetPageScaleOnActiveTree(float active_page_scale) { float clamped_page_scale = ClampPageScaleFactorToLimits(active_page_scale); // Temporary crash logging for https://crbug.com/845097. static bool has_dumped_without_crashing = false; - if (host_impl_->settings().is_layer_tree_for_subframe && + if (!host_impl_->settings().is_for_scalable_page && clamped_page_scale != 1.f && !has_dumped_without_crashing) { has_dumped_without_crashing = true; static auto* psf_oopif_error = base::debug::AllocateCrashKeyString( @@ -1196,10 +1221,8 @@ void LayerTreeImpl::SetPageScaleOnActiveTree(float active_page_scale) { psf_oopif_error, base::StringPrintf("%f", clamped_page_scale)); base::debug::DumpWithoutCrashing(); } - if (page_scale_factor()->SetCurrent(clamped_page_scale)) { + if (page_scale_factor()->SetCurrent(clamped_page_scale)) DidUpdatePageScale(); - UpdatePageScaleNode(); - } } void LayerTreeImpl::PushPageScaleFromMainThread(float page_scale_factor, @@ -1230,10 +1253,6 @@ void LayerTreeImpl::PushPageScaleFactorAndLimits(const float* page_scale_factor, if (changed_page_scale) DidUpdatePageScale(); - - DCHECK(lifecycle().AllowsPropertyTreeAccess()); - if (page_scale_factor) - UpdatePageScaleNode(); } void LayerTreeImpl::SetBrowserControlsParams( @@ -1338,27 +1357,33 @@ bool LayerTreeImpl::SetPageScaleFactorLimits(float min_page_scale_factor, } void LayerTreeImpl::DidUpdatePageScale() { - if (IsActiveTree()) + if (IsActiveTree()) { page_scale_factor()->SetCurrent( ClampPageScaleFactorToLimits(current_page_scale_factor())); - set_needs_update_draw_properties(); - - // Viewport scrollbar sizes depend on the page scale factor. - SetScrollbarGeometriesNeedUpdate(); + // Ensure the other trees are kept in sync. + if (host_impl_->pending_tree()) + host_impl_->pending_tree()->DidUpdatePageScale(); + if (host_impl_->recycle_tree()) + host_impl_->recycle_tree()->DidUpdatePageScale(); - if (IsActiveTree()) { if (settings().scrollbar_flash_after_any_scroll_update) { host_impl_->FlashAllScrollbars(true); - return; - } - if (auto* scroll_node = host_impl_->OuterViewportScrollNode()) { + } else if (auto* scroll_node = host_impl_->OuterViewportScrollNode()) { if (ScrollbarAnimationController* controller = host_impl_->ScrollbarAnimationControllerForElementId( scroll_node->element_id)) controller->DidScrollUpdate(); } } + + DCHECK(lifecycle().AllowsPropertyTreeAccess()); + UpdatePageScaleNode(); + + set_needs_update_draw_properties(); + + // Viewport scrollbar sizes depend on the page scale factor. + SetScrollbarGeometriesNeedUpdate(); } void LayerTreeImpl::SetDeviceScaleFactor(float device_scale_factor) { @@ -1564,11 +1589,14 @@ bool LayerTreeImpl::UpdateDrawProperties( this, &render_surface_list_, output_update_layer_list_for_testing); if (const char* client_name = GetClientNameForMetrics()) { - UMA_HISTOGRAM_COUNTS_1M( - base::StringPrintf( - "Compositing.%s.LayerTreeImpl.CalculateDrawPropertiesUs", - client_name), - timer.Elapsed().InMicroseconds()); + // This metric is only recorded for the Browser. + if (settings().single_thread_proxy_scheduler) { + UMA_HISTOGRAM_COUNTS_1M( + base::StringPrintf( + "Compositing.%s.LayerTreeImpl.CalculateDrawPropertiesUs", + client_name), + timer.Elapsed().InMicroseconds()); + } UMA_HISTOGRAM_COUNTS_100( base::StringPrintf("Compositing.%s.NumRenderSurfaces", client_name), base::saturated_cast<int>(render_surface_list_.size())); @@ -1854,6 +1882,10 @@ bool LayerTreeImpl::IsSyncTree() const { return host_impl_->sync_tree() == this; } +bool LayerTreeImpl::HasPendingTree() const { + return host_impl_->pending_tree() != nullptr; +} + LayerImpl* LayerTreeImpl::FindActiveTreeLayerById(int id) { LayerTreeImpl* tree = host_impl_->active_tree(); if (!tree) @@ -2154,6 +2186,11 @@ void LayerTreeImpl::RegisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer) { *scrollbar_layer_id = scrollbar_layer->id(); + if (IsActiveTree()) { + host_impl_->DidRegisterScrollbarLayer(scroll_element_id, + scrollbar_layer->orientation()); + } + if (IsActiveTree() && scrollbar_layer->is_overlay_scrollbar() && scrollbar_layer->GetScrollbarAnimator() != LayerTreeSettings::NO_ANIMATOR) { @@ -2895,4 +2932,25 @@ bool LayerTreeImpl::HasDocumentTransitionRequests() const { return !document_transition_requests_.empty(); } +bool LayerTreeImpl::IsReadyToActivate() const { + return host_impl_->IsReadyToActivate(); +} + +void LayerTreeImpl::ClearVisualUpdateDurations() { + previous_surfaces_visual_update_duration_ = base::TimeDelta(); + visual_update_duration_ = base::TimeDelta(); +} + +void LayerTreeImpl::SetVisualUpdateDurations( + base::TimeDelta previous_surfaces_visual_update_duration, + base::TimeDelta visual_update_duration) { + previous_surfaces_visual_update_duration_ = + previous_surfaces_visual_update_duration; + visual_update_duration_ = visual_update_duration; +} + +void LayerTreeImpl::RequestImplSideInvalidationForRerasterTiling() { + host_impl_->RequestImplSideInvalidationForRerasterTiling(); +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index fd335404e21..172bcc07769 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -139,6 +139,7 @@ class CC_EXPORT LayerTreeImpl { bool IsPendingTree() const; bool IsRecycleTree() const; bool IsSyncTree() const; + bool HasPendingTree() const; LayerImpl* FindActiveTreeLayerById(int id); LayerImpl* FindPendingTreeLayerById(int id); // TODO(bokan): PinchGestureActive is a layering violation, it's not related @@ -165,6 +166,8 @@ class CC_EXPORT LayerTreeImpl { const scoped_refptr<DisplayItemList>& display_list); TargetColorParams GetTargetColorParams( gfx::ContentColorUsage content_color_usage) const; + bool IsReadyToActivate() const; + void RequestImplSideInvalidationForRerasterTiling(); // Tree specific methods exposed to layer-impl tree. // --------------------------------------------------------------------------- @@ -221,9 +224,14 @@ class CC_EXPORT LayerTreeImpl { // Adapts an iterator of std::unique_ptr<LayerImpl> to an iterator of // LayerImpl*. template <typename Iterator> - class IteratorAdapter - : public std::iterator<std::forward_iterator_tag, LayerImpl*> { + class IteratorAdapter { public: + using iterator_category = std::forward_iterator_tag; + using value_type = LayerImpl*; + using difference_type = std::ptrdiff_t; + using pointer = LayerImpl**; + using reference = LayerImpl*&; + explicit IteratorAdapter(Iterator it) : it_(it) {} bool operator==(IteratorAdapter o) const { return it_ == o.it_; } bool operator!=(IteratorAdapter o) const { return !(*this == o); } @@ -278,6 +286,9 @@ class CC_EXPORT LayerTreeImpl { source_frame_number_ = frame_number; } + uint64_t trace_id() const { return trace_id_; } + void set_trace_id(uint64_t val) { trace_id_ = val; } + bool is_first_frame_after_commit() const { return source_frame_number_ != is_first_frame_after_commit_tracker_; } @@ -432,13 +443,17 @@ class CC_EXPORT LayerTreeImpl { float page_scale_factor_for_scroll() const { DCHECK(external_page_scale_factor_ == 1.f || current_page_scale_factor() == 1.f || - !settings().is_layer_tree_for_subframe); + settings().is_for_scalable_page); return external_page_scale_factor_ * current_page_scale_factor(); } const gfx::DisplayColorSpaces& display_color_spaces() const { return display_color_spaces_; } + const ViewportPropertyIds& viewport_property_ids() const { + return viewport_property_ids_; + } + SyncedElasticOverscroll* elastic_overscroll() { return elastic_overscroll_.get(); } @@ -492,11 +507,6 @@ class CC_EXPORT LayerTreeImpl { void ForceRedrawNextActivation() { next_activation_forces_redraw_ = true; } - void set_has_ever_been_drawn(bool has_drawn) { - has_ever_been_drawn_ = has_drawn; - } - bool has_ever_been_drawn() const { return has_ever_been_drawn_; } - void set_ui_resource_request_queue(UIResourceRequestQueue queue); const RenderSurfaceList& GetRenderSurfaceList() const; @@ -783,6 +793,17 @@ class CC_EXPORT LayerTreeImpl { bool HasDocumentTransitionRequests() const; + void ClearVisualUpdateDurations(); + void SetVisualUpdateDurations( + base::TimeDelta previous_surfaces_visual_update_duration, + base::TimeDelta visual_update_duration); + base::TimeDelta previous_surfaces_visual_update_duration() const { + return previous_surfaces_visual_update_duration_; + } + base::TimeDelta visual_update_duration() const { + return visual_update_duration_; + } + protected: float ClampPageScaleFactorToLimits(float page_scale_factor) const; void PushPageScaleFactorAndLimits(const float* page_scale_factor, @@ -810,6 +831,7 @@ class CC_EXPORT LayerTreeImpl { raw_ptr<LayerTreeHostImpl> host_impl_; int source_frame_number_; + uint64_t trace_id_ = 0; int is_first_frame_after_commit_tracker_; raw_ptr<HeadsUpDisplayLayerImpl> hud_layer_; PropertyTrees property_trees_; @@ -896,8 +918,6 @@ class CC_EXPORT LayerTreeImpl { bool next_activation_forces_redraw_; - bool has_ever_been_drawn_; - bool handle_visibility_changed_; std::vector<std::unique_ptr<SwapPromise>> swap_promise_list_; @@ -942,6 +962,13 @@ class CC_EXPORT LayerTreeImpl { // Document transition requests to be transferred to Viz. std::vector<std::unique_ptr<DocumentTransitionRequest>> document_transition_requests_; + + // The cumulative time spent performing visual updates for all Surfaces before + // this one. + base::TimeDelta previous_surfaces_visual_update_duration_; + // The cumulative time spent performing visual updates for the current + // Surface. + base::TimeDelta visual_update_duration_; }; } // namespace cc diff --git a/chromium/cc/trees/layer_tree_mutator.h b/chromium/cc/trees/layer_tree_mutator.h index fa3b501754c..939a54f9115 100644 --- a/chromium/cc/trees/layer_tree_mutator.h +++ b/chromium/cc/trees/layer_tree_mutator.h @@ -5,18 +5,19 @@ #ifndef CC_TREES_LAYER_TREE_MUTATOR_H_ #define CC_TREES_LAYER_TREE_MUTATOR_H_ +#include <memory> +#include <string> +#include <unordered_map> +#include <vector> + #include "base/callback_forward.h" +#include "base/check.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 "third_party/abseil-cpp/absl/types/optional.h" -#include <memory> -#include <string> -#include <unordered_map> -#include <vector> - namespace cc { // TOOD(kevers): Remove kDrop once confirmed that it is no longer needed under diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index f6094a5defe..8dfe968b631 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -114,7 +114,11 @@ class CC_EXPORT LayerTreeSettings { // Indicates the case when a sub-frame gets its own LayerTree because it's // rendered in a different process from its ancestor frames. - bool is_layer_tree_for_subframe = false; + bool is_for_embedded_frame = false; + + // Indicates when the LayerTree is for a portal element, GuestView, or top + // level frame. In all these cases we may have a page scale. + bool is_for_scalable_page = true; // Determines whether we disallow non-exact matches when finding resources // in ResourcePool. Only used for layout or pixel tests, as non-deterministic @@ -204,6 +208,10 @@ class CC_EXPORT LayerTreeSettings { // even if the layer is not drawn. For example, if the layer is occluded it is // still considered drawn and will not be impacted by this feature. bool release_tile_resources_for_hidden_layers = false; + + // Whether Fluent scrollbar is enabled. Please check https://crbug.com/1292117 + // to find the link to the Fluent Scrollbar spec and related CLs. + bool enable_fluent_scrollbar = false; }; class CC_EXPORT LayerListSettings : public LayerTreeSettings { diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h index 0c344bb1b9e..819856cde5a 100644 --- a/chromium/cc/trees/mutator_host.h +++ b/chromium/cc/trees/mutator_host.h @@ -82,29 +82,14 @@ class MutatorHost { virtual bool ScrollOffsetAnimationWasInterrupted( ElementId element_id) const = 0; - 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( - ElementId element_id, - ElementListType list_type) const = 0; + virtual bool IsAnimatingProperty(ElementId element_id, + ElementListType list_type, + TargetProperty::Type property) const = 0; - virtual bool HasPotentiallyRunningFilterAnimation( - ElementId element_id, - ElementListType list_type) const = 0; - virtual bool HasPotentiallyRunningBackdropFilterAnimation( + virtual bool HasPotentiallyRunningAnimationForProperty( ElementId element_id, - ElementListType list_type) const = 0; - virtual bool HasPotentiallyRunningOpacityAnimation( - ElementId element_id, - ElementListType list_type) const = 0; - virtual bool HasPotentiallyRunningTransformAnimation( - ElementId element_id, - ElementListType list_type) const = 0; + ElementListType list_type, + TargetProperty::Type property) const = 0; virtual bool HasAnyAnimationTargetingProperty( ElementId element_id, @@ -156,6 +141,7 @@ class MutatorHost { virtual bool HasCanvasInvalidation() const = 0; virtual bool HasJSAnimation() const = 0; virtual bool HasSmilAnimation() const = 0; + virtual bool HasSharedElementTransition() const = 0; // Iterates through all animations and returns the minimum tick interval. // Returns 0 if there is a continuous animation which should be ticked diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc index 5a2ac9990a6..7a3bb079487 100644 --- a/chromium/cc/trees/property_tree.cc +++ b/chromium/cc/trees/property_tree.cc @@ -22,6 +22,7 @@ #include "cc/trees/property_tree.h" #include "cc/trees/scroll_node.h" #include "cc/trees/transform_node.h" +#include "cc/trees/viewport_property_ids.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "ui/gfx/geometry/outsets_f.h" #include "ui/gfx/geometry/point_conversions.h" @@ -57,7 +58,6 @@ PropertyTree<T>& PropertyTree<T>::operator=(const PropertyTree<T>&) = default; TransformTree::TransformTree(PropertyTrees* property_trees) : PropertyTree<TransformNode>(property_trees), page_scale_factor_(1.f), - overscroll_node_id_(kInvalidPropertyNodeId), fixed_elements_dont_overscroll_(false), device_scale_factor_(1.f), device_transform_scale_factor_(1.f) { @@ -128,7 +128,6 @@ void TransformTree::clear() { PropertyTree<TransformNode>::clear(); page_scale_factor_ = 1.f; - overscroll_node_id_ = kInvalidPropertyNodeId; fixed_elements_dont_overscroll_ = false; device_scale_factor_ = 1.f; device_transform_scale_factor_ = 1.f; @@ -174,14 +173,16 @@ void TransformTree::ResetChangeTracking() { } } -void TransformTree::UpdateTransforms(int id) { +void TransformTree::UpdateTransforms( + int id, + const ViewportPropertyIds* viewport_property_ids) { TransformNode* node = Node(id); TransformNode* parent_node = parent(node); DCHECK(parent_node); // TODO(flackr): Only dirty when scroll offset changes. if (node->sticky_position_constraint_id >= 0 || node->needs_local_transform_update || ShouldUndoOverscroll(node)) { - UpdateLocalTransform(node); + UpdateLocalTransform(node, viewport_property_ids); } else { UndoSnapping(node); } @@ -460,12 +461,19 @@ bool TransformTree::ShouldUndoOverscroll(const TransformNode* node) const { void TransformTree::UpdateFixedNodeTransformAndClip( const TransformNode* node, - gfx::Vector2dF& fixed_position_adjustment) { - if (!ShouldUndoOverscroll(node) || - overscroll_node_id_ == kInvalidPropertyNodeId) + gfx::Vector2dF& fixed_position_adjustment, + const ViewportPropertyIds* viewport_property_ids) { + const int transform_id = + viewport_property_ids + ? viewport_property_ids->overscroll_elasticity_transform + : kInvalidPropertyNodeId; + const int clip_id = viewport_property_ids ? viewport_property_ids->outer_clip + : kInvalidPropertyNodeId; + if (!ShouldUndoOverscroll(node) || transform_id == kInvalidPropertyNodeId || + clip_id == kInvalidPropertyNodeId) return; - const TransformNode* overscroll_node = Node(overscroll_node_id_); + const TransformNode* overscroll_node = Node(transform_id); const gfx::Vector2dF overscroll_offset = overscroll_node->scroll_offset.OffsetFromOrigin(); if (overscroll_offset.IsZero()) @@ -475,24 +483,24 @@ void TransformTree::UpdateFixedNodeTransformAndClip( gfx::ScaleVector2d(overscroll_offset, 1.f / page_scale_factor()); ClipTree& clip_tree = property_trees()->clip_tree_mutable(); - ClipNode* clip_node = clip_tree.Node(clip_tree.overscroll_node_id()); - - if (clip_node) { - // Inflate the clip rect based on the overscroll direction. - gfx::OutsetsF outsets; - fixed_position_adjustment.x() < 0 - ? outsets.set_left(-fixed_position_adjustment.x()) - : outsets.set_right(fixed_position_adjustment.x()); - fixed_position_adjustment.y() < 0 - ? outsets.set_top(-fixed_position_adjustment.y()) - : outsets.set_bottom(fixed_position_adjustment.y()); - - clip_node->clip.Outset(outsets); - clip_tree.set_needs_update(true); - } -} - -void TransformTree::UpdateLocalTransform(TransformNode* node) { + ClipNode* clip_node = clip_tree.Node(clip_id); + DCHECK(clip_node); + + // Inflate the clip rect based on the overscroll direction. + gfx::OutsetsF outsets; + fixed_position_adjustment.x() < 0 + ? outsets.set_left(-fixed_position_adjustment.x()) + : outsets.set_right(fixed_position_adjustment.x()); + fixed_position_adjustment.y() < 0 + ? outsets.set_top(-fixed_position_adjustment.y()) + : outsets.set_bottom(fixed_position_adjustment.y()); + clip_node->clip.Outset(outsets); + clip_tree.set_needs_update(true); +} + +void TransformTree::UpdateLocalTransform( + TransformNode* node, + const ViewportPropertyIds* viewport_property_ids) { gfx::Transform transform; transform.Translate3d(node->post_translation.x() + node->origin.x(), node->post_translation.y() + node->origin.y(), @@ -504,7 +512,8 @@ void TransformTree::UpdateLocalTransform(TransformNode* node) { property_trees()->outer_viewport_container_bounds_delta().y()); } - UpdateFixedNodeTransformAndClip(node, fixed_position_adjustment); + UpdateFixedNodeTransformAndClip(node, fixed_position_adjustment, + viewport_property_ids); transform.Translate(fixed_position_adjustment - node->scroll_offset.OffsetFromOrigin()); transform.Translate(StickyPositionOffset(node)); @@ -709,7 +718,6 @@ void TransformTree::SetToScreen(int node_id, const gfx::Transform& transform) { bool TransformTree::operator==(const TransformTree& other) const { return PropertyTree::operator==(other) && page_scale_factor_ == other.page_scale_factor() && - overscroll_node_id_ == other.overscroll_node_id() && fixed_elements_dont_overscroll_ == other.fixed_elements_dont_overscroll() && device_scale_factor_ == other.device_scale_factor() && @@ -1265,8 +1273,7 @@ EffectTree::CopyRequestMap EffectTree::TakeCopyRequests() { } ClipTree::ClipTree(PropertyTrees* property_trees) - : PropertyTree<ClipNode>(property_trees), - overscroll_node_id_(kInvalidPropertyNodeId) {} + : PropertyTree<ClipNode>(property_trees) {} void ClipTree::SetViewportClip(gfx::RectF viewport_rect) { if (size() < 2) @@ -1286,8 +1293,7 @@ gfx::RectF ClipTree::ViewportClip() const { #if DCHECK_IS_ON() bool ClipTree::operator==(const ClipTree& other) const { - return PropertyTree::operator==(other) && - overscroll_node_id_ == other.overscroll_node_id(); + return PropertyTree::operator==(other); } #endif @@ -1964,6 +1970,9 @@ bool PropertyTrees::ElementIsAnimatingChanged( const ElementId element_id = it->second; switch (property) { case TargetProperty::TRANSFORM: + case TargetProperty::SCALE: + case TargetProperty::ROTATE: + case TargetProperty::TRANSLATE: if (TransformNode* transform_node = transform_tree_mutable().FindNodeFromElementId(element_id)) { if (mask.currently_running[property]) diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h index 12ecb6eb4af..78f52a32cbc 100644 --- a/chromium/cc/trees/property_tree.h +++ b/chromium/cc/trees/property_tree.h @@ -53,6 +53,7 @@ class LayerTreeImpl; class RenderSurfaceImpl; struct RenderSurfacePropertyChangedFlags; struct CompositorCommitData; +struct ViewportPropertyIds; using SyncedScrollOffset = SyncedProperty<AdditionGroup<gfx::PointF, gfx::Vector2dF>>; @@ -182,7 +183,9 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { const gfx::Transform& transform); void ResetChangeTracking(); // Updates the parent, target, and screen space transforms and snapping. - void UpdateTransforms(int id); + void UpdateTransforms( + int id, + const ViewportPropertyIds* viewport_property_ids = nullptr); void UpdateTransformChanged(TransformNode* node, TransformNode* parent_node); void UpdateNodeAndAncestorsAreAnimatedOrInvertible( TransformNode* node, @@ -199,8 +202,6 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { } float page_scale_factor() const { return page_scale_factor_; } - void set_overscroll_node_id(int id) { overscroll_node_id_ = id; } - int overscroll_node_id() const { return overscroll_node_id_; } void set_fixed_elements_dont_overscroll(bool value) { fixed_elements_dont_overscroll_ = value; } @@ -249,7 +250,8 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { bool ShouldUndoOverscroll(const TransformNode* node) const; void UpdateFixedNodeTransformAndClip( const TransformNode* node, - gfx::Vector2dF& fixed_position_adjustment); + gfx::Vector2dF& fixed_position_adjustment, + const ViewportPropertyIds* viewport_property_ids); const StickyPositionNodeData* GetStickyPositionData(int node_id) const { return const_cast<TransformTree*>(this)->MutableStickyPositionData(node_id); @@ -276,7 +278,8 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { StickyPositionNodeData* MutableStickyPositionData(int node_id); gfx::Vector2dF StickyPositionOffset(TransformNode* node); - void UpdateLocalTransform(TransformNode* node); + void UpdateLocalTransform(TransformNode* node, + const ViewportPropertyIds* viewport_property_ids); void UpdateScreenSpaceTransform(TransformNode* node, TransformNode* parent_node); void UpdateAnimationProperties(TransformNode* node, @@ -291,7 +294,6 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { // scale is calculated using page scale factor, device scale factor and the // scale factor of device transform. So we need to store them explicitly. float page_scale_factor_; - int overscroll_node_id_; bool fixed_elements_dont_overscroll_; float device_scale_factor_; float device_transform_scale_factor_; @@ -333,14 +335,6 @@ class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> { void SetViewportClip(gfx::RectF viewport_rect); gfx::RectF ViewportClip() const; - - void set_overscroll_node_id(int id) { overscroll_node_id_ = id; } - int overscroll_node_id() const { return overscroll_node_id_; } - - private: - // Used to track the ClipNode that is corresponding to the overscroll - // TransformNode. - int overscroll_node_id_; }; class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> { diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc index 20c374bd36d..00eb3a85b00 100644 --- a/chromium/cc/trees/property_tree_builder.cc +++ b/chromium/cc/trees/property_tree_builder.cc @@ -112,14 +112,16 @@ class PropertyTreeBuilderContext { // Methods to query state from the AnimationHost ---------------------- bool OpacityIsAnimating(const MutatorHost& host, Layer* layer) { - return host.IsAnimatingOpacityProperty(layer->element_id(), - layer->GetElementTypeForAnimation()); + return host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::OPACITY); } bool HasPotentiallyRunningOpacityAnimation(const MutatorHost& host, Layer* layer) { - return host.HasPotentiallyRunningOpacityAnimation( - layer->element_id(), layer->GetElementTypeForAnimation()); + return host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::OPACITY); } bool HasPotentialOpacityAnimation(const MutatorHost& host, Layer* layer) { @@ -128,25 +130,49 @@ bool HasPotentialOpacityAnimation(const MutatorHost& host, Layer* layer) { } bool FilterIsAnimating(const MutatorHost& host, Layer* layer) { - return host.IsAnimatingFilterProperty(layer->element_id(), - layer->GetElementTypeForAnimation()); + return host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::FILTER); } bool HasPotentiallyRunningFilterAnimation(const MutatorHost& host, Layer* layer) { - return host.HasPotentiallyRunningFilterAnimation( - layer->element_id(), layer->GetElementTypeForAnimation()); + return host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::FILTER); } bool TransformIsAnimating(const MutatorHost& host, Layer* layer) { - return host.IsAnimatingTransformProperty(layer->element_id(), - layer->GetElementTypeForAnimation()); + DCHECK(!host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::SCALE) && + !host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::ROTATE) && + !host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::TRANSLATE)) + << "individual transform properties only supported in layer lists mode"; + return host.IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::TRANSFORM); } bool HasPotentiallyRunningTransformAnimation(const MutatorHost& host, Layer* layer) { - return host.HasPotentiallyRunningTransformAnimation( - layer->element_id(), layer->GetElementTypeForAnimation()); + DCHECK(!host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::SCALE) && + !host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::ROTATE) && + !host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::TRANSLATE)) + << "individual transform properties only supported in layer lists mode"; + return host.HasPotentiallyRunningAnimationForProperty( + layer->element_id(), layer->GetElementTypeForAnimation(), + TargetProperty::TRANSFORM); } float MaximumAnimationScale(const MutatorHost& host, Layer* layer) { @@ -236,6 +262,13 @@ bool PropertyTreeBuilderContext::AddTransformNodeIfNeeded( // the Running state right after commit on the compositor thread. const bool has_any_transform_animation = HasAnyAnimationTargetingProperty( mutator_host_, layer, TargetProperty::TRANSFORM); + DCHECK(!HasAnyAnimationTargetingProperty(mutator_host_, layer, + TargetProperty::SCALE) && + !HasAnyAnimationTargetingProperty(mutator_host_, layer, + TargetProperty::ROTATE) && + !HasAnyAnimationTargetingProperty(mutator_host_, layer, + TargetProperty::TRANSLATE)) + << "individual transform properties only supported in layer lists mode"; const bool has_surface = created_render_surface; @@ -683,13 +716,15 @@ void PropertyTreeBuilderContext::AddScrollNodeIfNeeded( void SetSafeOpaqueBackgroundColor(const DataForRecursion& data_from_ancestor, Layer* layer, DataForRecursion* data_for_children) { - SkColor background_color = layer->background_color(); + // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f. + SkColor background_color = layer->background_color().toSkColor(); data_for_children->safe_opaque_background_color = SkColorGetA(background_color) == 255 ? background_color : data_from_ancestor.safe_opaque_background_color; + // TODO(crbug/1308932): Remove FromColor and make all SkColor4f. layer->SetSafeOpaqueBackgroundColor( - data_for_children->safe_opaque_background_color); + SkColor4f::FromColor(data_for_children->safe_opaque_background_color)); } void PropertyTreeBuilderContext::BuildPropertyTreesInternal( diff --git a/chromium/cc/trees/property_tree_builder_unittest.cc b/chromium/cc/trees/property_tree_builder_unittest.cc index b5639ee0e11..5b5f96f4476 100644 --- a/chromium/cc/trees/property_tree_builder_unittest.cc +++ b/chromium/cc/trees/property_tree_builder_unittest.cc @@ -489,8 +489,9 @@ TEST_F(PropertyTreeBuilderTest, AnimatedOpacityCreatesRenderSurface) { static bool FilterIsAnimating(LayerImpl* layer) { MutatorHost* host = layer->layer_tree_impl()->mutator_host(); - return host->IsAnimatingFilterProperty(layer->element_id(), - layer->GetElementTypeForAnimation()); + return host->IsAnimatingProperty(layer->element_id(), + layer->GetElementTypeForAnimation(), + TargetProperty::FILTER); } // Verify that having an animated filter (but no current filter, as these @@ -526,8 +527,9 @@ TEST_F(PropertyTreeBuilderTest, AnimatedFilterCreatesRenderSurface) { bool HasPotentiallyRunningFilterAnimation(const LayerImpl& layer) { MutatorHost* host = layer.layer_tree_impl()->mutator_host(); - return host->HasPotentiallyRunningFilterAnimation( - layer.element_id(), layer.GetElementTypeForAnimation()); + return host->HasPotentiallyRunningAnimationForProperty( + layer.element_id(), layer.GetElementTypeForAnimation(), + TargetProperty::FILTER); } // Verify that having a filter animation with a delayed start time creates a diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc index b2ec896d7a4..13dcfc9ab46 100644 --- a/chromium/cc/trees/property_tree_unittest.cc +++ b/chromium/cc/trees/property_tree_unittest.cc @@ -16,6 +16,7 @@ #include "cc/trees/layer_tree_impl.h" #include "cc/trees/scroll_node.h" #include "cc/trees/transform_node.h" +#include "cc/trees/viewport_property_ids.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/test/geometry_util.h" @@ -202,6 +203,7 @@ TEST(PropertyTreeTest, FixedElementInverseTranslation) { FakeProtectedSequenceSynchronizer synchronizer; PropertyTrees property_trees(synchronizer); + ViewportPropertyIds viewport_property_ids; ClipTree& clip_tree = property_trees.clip_tree_mutable(); const gfx::RectF clip_rect(0, 0, 100, 100); ClipNode clip_node; @@ -209,20 +211,20 @@ TEST(PropertyTreeTest, FixedElementInverseTranslation) { clip_node.parent_id = 0; clip_node.clip = clip_rect; clip_tree.Insert(clip_node, 0); - clip_tree.set_overscroll_node_id(clip_node.id); + viewport_property_ids.outer_clip = clip_node.id; TransformTree& transform_tree = property_trees.transform_tree_mutable(); TransformNode contents_root; contents_root.local.Translate(2, 2); contents_root.id = transform_tree.Insert(contents_root, 0); - transform_tree.UpdateTransforms(1); + transform_tree.UpdateTransforms(1, &viewport_property_ids); const gfx::PointF overscroll_offset(0, 10); TransformNode overscroll_node; overscroll_node.scroll_offset = overscroll_offset; overscroll_node.id = transform_tree.Insert(overscroll_node, 1); + viewport_property_ids.overscroll_elasticity_transform = overscroll_node.id; - transform_tree.set_overscroll_node_id(overscroll_node.id); transform_tree.set_fixed_elements_dont_overscroll(true); TransformNode fixed_node; @@ -231,8 +233,9 @@ TEST(PropertyTreeTest, FixedElementInverseTranslation) { EXPECT_TRUE(transform_tree.ShouldUndoOverscroll(&fixed_node)); - transform_tree.UpdateTransforms(2); // overscroll_node - transform_tree.UpdateTransforms(3); // fixed_node + transform_tree.UpdateTransforms(2, + &viewport_property_ids); // overscroll_node + transform_tree.UpdateTransforms(3, &viewport_property_ids); // fixed_node gfx::Transform expected; expected.Translate(overscroll_offset.OffsetFromOrigin()); @@ -240,7 +243,7 @@ TEST(PropertyTreeTest, FixedElementInverseTranslation) { gfx::RectF expected_clip_rect(clip_rect); expected_clip_rect.set_height(clip_rect.height() + overscroll_offset.y()); - EXPECT_EQ(clip_tree.Node(clip_tree.overscroll_node_id())->clip, + EXPECT_EQ(clip_tree.Node(viewport_property_ids.outer_clip)->clip, expected_clip_rect); } @@ -279,7 +282,7 @@ TEST(PropertyTreeTest, TransformsWithFlattening) { tree.Node(grand_child)->local = rotation_about_x; tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); property_trees.ResetCachedData(); gfx::Transform flattened_rotation_about_x = rotation_about_x; @@ -306,7 +309,7 @@ TEST(PropertyTreeTest, TransformsWithFlattening) { // Remove flattening at grand_child, and recompute transforms. tree.Node(grand_child)->flattens_inherited_transform = false; tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); property_trees.GetToTarget(grand_child, effect_parent, &to_target); EXPECT_TRANSFORM_EQ(rotation_about_x * rotation_about_x, to_target); @@ -417,7 +420,7 @@ TEST(PropertyTreeTest, ComputeTransformToTargetWithZeroSurfaceContentsScale) { tree.Node(grand_parent_id)->needs_local_transform_update = true; tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); transform.MakeIdentity(); tree.CombineTransformsBetween(child_id, grand_parent_id, &transform); @@ -428,7 +431,7 @@ TEST(PropertyTreeTest, ComputeTransformToTargetWithZeroSurfaceContentsScale) { tree.Node(grand_parent_id)->needs_local_transform_update = true; tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); transform.MakeIdentity(); tree.CombineTransformsBetween(child_id, grand_parent_id, &transform); @@ -456,7 +459,7 @@ TEST(PropertyTreeTest, FlatteningWhenDestinationHasOnlyFlatAncestors) { tree.Node(grand_child)->flattens_inherited_transform = true; tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); gfx::Transform flattened_rotation_about_x = rotation_about_x; flattened_rotation_about_x.FlattenTo2d(); @@ -511,7 +514,7 @@ TEST(PropertyTreeTest, SingularTransformSnapTest) { child_node->local.Translate(1.3f, 1.3f); tree.set_needs_update(true); - draw_property_utils::ComputeTransforms(&tree); + draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds()); property_trees.ResetCachedData(); gfx::Transform from_target; diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h index ce648e1d98c..6c879ed922d 100644 --- a/chromium/cc/trees/proxy.h +++ b/chromium/cc/trees/proxy.h @@ -101,9 +101,6 @@ class CC_EXPORT Proxy { virtual void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) = 0; - virtual void SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) = 0; - // Returns a percentage representing average throughput of last X seconds. // Only implemenented for single threaded proxy. virtual uint32_t GetAverageThroughput() const = 0; diff --git a/chromium/cc/trees/proxy_common.h b/chromium/cc/trees/proxy_common.h index d8b8725949a..a1d9117c252 100644 --- a/chromium/cc/trees/proxy_common.h +++ b/chromium/cc/trees/proxy_common.h @@ -31,6 +31,7 @@ struct CC_EXPORT BeginMainFrameAndCommitState { ActiveFrameSequenceTrackers active_sequence_trackers = 0; bool evicted_ui_resources = false; std::vector<uint32_t> finished_transition_request_sequence_ids; + uint64_t trace_id = 0; }; } // namespace cc diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc index d7a12d0a16f..e253b21d1ba 100644 --- a/chromium/cc/trees/proxy_impl.cc +++ b/chromium/cc/trees/proxy_impl.cc @@ -77,9 +77,9 @@ class ScopedCommitCompletionEvent { } private: - CompletionEvent* const event_; + const raw_ptr<CompletionEvent> event_; CommitTimestamps commit_timestamps_; - base::SingleThreadTaskRunner* main_thread_task_runner_; + raw_ptr<base::SingleThreadTaskRunner> main_thread_task_runner_; base::WeakPtr<ProxyMain> proxy_main_weak_ptr_; }; @@ -188,10 +188,34 @@ void ProxyImpl::InitializeLayerTreeFrameSinkOnImpl( scheduler_->DidCreateAndInitializeLayerTreeFrameSink(); } -void ProxyImpl::SetDeferBeginMainFrameOnImpl( - bool defer_begin_main_frame) const { +bool ProxyImpl::ShouldDeferBeginMainFrame() const { + return main_wants_defer_begin_main_frame_ || + impl_wants_defer_begin_main_frame_; +} + +void ProxyImpl::SetDeferBeginMainFrameFromMain(bool defer_begin_main_frame) { + // This is the impl-side update of a main-thread request (that is, through + // ProxyMain::SetDeferMainFrameUpdate) to defer BeginMainFrame. + DCHECK(IsImplThread()); + bool was_deferring = ShouldDeferBeginMainFrame(); + + main_wants_defer_begin_main_frame_ = defer_begin_main_frame; + + bool should_defer = ShouldDeferBeginMainFrame(); + if (was_deferring != should_defer) + scheduler_->SetDeferBeginMainFrame(ShouldDeferBeginMainFrame()); +} + +void ProxyImpl::SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) { + // This is a request from the impl thread to defer BeginMainFrame. DCHECK(IsImplThread()); - scheduler_->SetDeferBeginMainFrame(defer_begin_main_frame); + bool was_deferring = ShouldDeferBeginMainFrame(); + + impl_wants_defer_begin_main_frame_ = defer_begin_main_frame; + + bool should_defer = ShouldDeferBeginMainFrame(); + if (was_deferring != should_defer) + scheduler_->SetDeferBeginMainFrame(ShouldDeferBeginMainFrame()); } void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { @@ -201,7 +225,6 @@ void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { } void ProxyImpl::SetNeedsCommitOnImpl() { - DCHECK(IsImplThread()); SetNeedsCommitOnImplThread(); } @@ -287,6 +310,14 @@ void ProxyImpl::FrameSinksToThrottleUpdated( NOTREACHED(); } +void ProxyImpl::ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) { + DCHECK(IsImplThread()); + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&ProxyMain::ReportEventLatency, + proxy_main_weak_ptr_, std::move(latencies))); +} + void ProxyImpl::NotifyReadyToCommitOnImpl( CompletionEvent* completion_event, std::unique_ptr<CommitState> commit_state, @@ -295,7 +326,12 @@ void ProxyImpl::NotifyReadyToCommitOnImpl( const viz::BeginFrameArgs& commit_args, CommitTimestamps* commit_timestamps, bool commit_timeout) { - TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToCommitOnImpl"); + { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.NotifyReadyToCommitOnImpl", + TRACE_ID_LOCAL(commit_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + } DCHECK(!data_for_commit_.get()); DCHECK(IsImplThread()); DCHECK(base::FeatureList::IsEnabled(features::kNonBlockingCommit) || @@ -381,11 +417,22 @@ void ProxyImpl::OnCanDrawStateChanged(bool can_draw) { } void ProxyImpl::NotifyReadyToActivate() { - TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToActivate"); + if (host_impl_->sync_tree() && + !scheduler_->pending_tree_is_ready_for_activation()) { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.NotifyReadyToActivate", + TRACE_ID_LOCAL(host_impl_->sync_tree()->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + } DCHECK(IsImplThread()); scheduler_->NotifyReadyToActivate(); } +bool ProxyImpl::IsReadyToActivate() { + DCHECK(IsImplThread()); + return scheduler_->IsReadyToActivate(); +} + void ProxyImpl::NotifyReadyToDraw() { TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToDraw"); DCHECK(IsImplThread()); @@ -458,11 +505,6 @@ void ProxyImpl::RenewTreePriority() { bool user_interaction_in_progress = non_scroll_interaction_in_progress || scroll_type_considered_interaction; - if (host_impl_->ukm_manager()) { - host_impl_->ukm_manager()->SetUserInteractionInProgress( - user_interaction_in_progress); - } - if (host_impl_->CurrentScrollCheckerboardsDueToNoRecording() && base::FeatureList::IsEnabled( features::kPreferNewContentForCheckerboardedScrolls)) { @@ -665,7 +707,20 @@ void ProxyImpl::ScheduledActionSendBeginMainFrame( host_impl_->FrameSequenceTrackerActiveTypes(); begin_main_frame_state->evicted_ui_resources = host_impl_->EvictedUIResourcesExist(); + begin_main_frame_state->trace_id = + (0x1llu << 51) | // Signature bit chosen at random to avoid collisions + (args.frame_id.source_id << 32) | + (args.frame_id.sequence_number & 0xffffffff); host_impl_->WillSendBeginMainFrame(); + { + TRACE_EVENT_WITH_FLOW1( + "viz,benchmark", "Graphics.Pipeline", TRACE_ID_GLOBAL(args.trace_id), + TRACE_EVENT_FLAG_FLOW_IN, "step", "SendBeginMainFrame"); + TRACE_EVENT_WITH_FLOW0("viz,benchmark", + "MainFrame.SendBeginMainFrameOnImpl", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_OUT); + } MainThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_, @@ -693,7 +748,12 @@ DrawResult ProxyImpl::ScheduledActionDrawForced() { } void ProxyImpl::ScheduledActionCommit() { - TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionCommit"); + { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.BeginCommit", + TRACE_ID_LOCAL(data_for_commit_->commit_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + } DCHECK(IsImplThread()); DCHECK(base::FeatureList::IsEnabled(features::kNonBlockingCommit) || IsMainThreadBlocked()); @@ -707,8 +767,9 @@ void ProxyImpl::ScheduledActionCommit() { allow_cross_thread_ref_count_access; auto* commit_state = data_for_commit_->commit_state.get(); - auto* unsafe_state = data_for_commit_->unsafe_state; - host_impl_->BeginCommit(commit_state->source_frame_number); + auto* unsafe_state = data_for_commit_->unsafe_state.get(); + host_impl_->BeginCommit(commit_state->source_frame_number, + commit_state->trace_id); host_impl_->FinishCommit(*commit_state, *unsafe_state); base::TimeTicks finish_time = base::TimeTicks::Now(); if (data_for_commit_->commit_timestamps) @@ -725,16 +786,30 @@ void ProxyImpl::ScheduledActionCommit() { } data_for_commit_.reset(); - scheduler_->DidCommit(); - // Delay this step until afer the main thread has been released as it's - // often a good bit of work to update the tree and prepare the new frame. - host_impl_->CommitComplete(); +} + +void ProxyImpl::ScheduledActionPostCommit() { + DCHECK(IsImplThread()); + TRACE_EVENT_WITH_FLOW0("viz,benchmark", "MainFrame.CommitComplete", + TRACE_ID_LOCAL(host_impl_->sync_tree()->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + // This is run as a separate step from commit because it can be time-consuming + // and ought not delay sending the next BeginMainFrame. + host_impl_->CommitComplete(); + // TODO(szager): This should be set at activation time. crbug.com/1323906 next_frame_is_newly_committed_frame_ = true; } void ProxyImpl::ScheduledActionActivateSyncTree() { - TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionActivateSyncTree"); + if (host_impl_->sync_tree() && + host_impl_->sync_tree()->source_frame_number() != + host_impl_->active_tree()->source_frame_number()) { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.Activate", + TRACE_ID_LOCAL(host_impl_->sync_tree()->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + } DCHECK(IsImplThread()); host_impl_->ActivateSyncTree(); } @@ -785,6 +860,10 @@ DrawResult ProxyImpl::DrawInternal(bool forced_draw) { DCHECK(IsImplThread()); DCHECK(host_impl_.get()); + TRACE_EVENT_WITH_FLOW0("viz,benchmark", "MainFrame.Draw", + TRACE_ID_LOCAL(host_impl_->active_tree()->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + base::AutoReset<bool> mark_inside(&inside_draw_, true); // This method is called on a forced draw, regardless of whether we are able @@ -887,11 +966,6 @@ void ProxyImpl::SetRenderFrameObserver( host_impl_->SetRenderFrameObserver(std::move(observer)); } -void ProxyImpl::SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) { - host_impl_->SetEnableFrameRateThrottling(enable_frame_rate_throttling); -} - ProxyImpl::DataForCommit::DataForCommit( std::unique_ptr<ScopedCommitCompletionEvent> commit_completion_event, std::unique_ptr<CommitState> commit_state, diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h index 19cd52164e5..53859c996e7 100644 --- a/chromium/cc/trees/proxy_impl.h +++ b/chromium/cc/trees/proxy_impl.h @@ -56,7 +56,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, void InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator); void InitializePaintWorkletLayerPainterOnImpl( std::unique_ptr<PaintWorkletLayerPainter> painter); - void SetDeferBeginMainFrameOnImpl(bool defer_begin_main_frame) const; + void SetDeferBeginMainFrameFromMain(bool defer_begin_main_frame); void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect); void SetNeedsCommitOnImpl(); void SetTargetLocalSurfaceIdOnImpl( @@ -81,7 +81,6 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, base::WritableSharedMemoryMapping ukm_smoothness_data); void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer); - void SetEnableFrameRateThrottling(bool enable_frame_rate_throttling); void MainFrameWillHappenOnImplForTesting(CompletionEvent* completion, bool* main_frame_will_happen); @@ -97,6 +96,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, void DidReceiveCompositorFrameAckOnImplThread() override; void OnCanDrawStateChanged(bool can_draw) override; void NotifyReadyToActivate() override; + bool IsReadyToActivate() override; void NotifyReadyToDraw() override; // Please call these 2 functions through // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsOneBeginImplFrame(). @@ -105,6 +105,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, void SetNeedsPrepareTilesOnImplThread() override; void SetNeedsCommitOnImplThread() override; void SetVideoNeedsBeginFrames(bool needs_begin_frames) override; + void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override; bool IsInsideDraw() override; void RenewTreePriority() override; void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task, @@ -133,6 +134,8 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, bool IsInSynchronousComposite() const override; void FrameSinksToThrottleUpdated( const base::flat_set<viz::FrameSinkId>& id) override; + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) override; // SchedulerClient implementation bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override; @@ -146,6 +149,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, DrawResult ScheduledActionDrawIfPossible() override; DrawResult ScheduledActionDrawForced() override; void ScheduledActionCommit() override; + void ScheduledActionPostCommit() override; void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginLayerTreeFrameSinkCreation() override; void ScheduledActionPrepareTiles() override; @@ -162,6 +166,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, bool IsImplThread() const; bool IsMainThreadBlocked() const; base::SingleThreadTaskRunner* MainThreadTaskRunner(); + bool ShouldDeferBeginMainFrame() const; const int layer_tree_host_id_; @@ -181,10 +186,10 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, // Set when the main thread is waiting on a commit to complete. std::unique_ptr<ScopedCommitCompletionEvent> commit_completion_event; std::unique_ptr<CommitState> commit_state; - const ThreadUnsafeCommitState* unsafe_state; + raw_ptr<const ThreadUnsafeCommitState> unsafe_state; // This is passed from the main thread so the impl thread can record // timestamps at the beginning and end of commit. - CommitTimestamps* commit_timestamps = nullptr; + raw_ptr<CommitTimestamps> commit_timestamps = nullptr; }; std::unique_ptr<DataForCommit> data_for_commit_; @@ -218,6 +223,10 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, // A weak pointer to ProxyMain that is invalidated when LayerTreeFrameSink is // released. base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr_; + + // Either thread can request deferring BeginMainFrame; keep track of both. + bool main_wants_defer_begin_main_frame_ = false; + bool impl_wants_defer_begin_main_frame_ = false; }; } // namespace cc diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc index 0f36361559d..4bd1151680d 100644 --- a/chromium/cc/trees/proxy_main.cc +++ b/chromium/cc/trees/proxy_main.cc @@ -131,11 +131,19 @@ void ProxyMain::BeginMainFrame( DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_); DCHECK(!layer_tree_host_->in_commit()); + { + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.BeginMainFrameOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + } base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now(); + const viz::BeginFrameArgs& frame_args = + begin_main_frame_state->begin_frame_args; benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( benchmark_instrumentation::kDoBeginFrame, - begin_main_frame_state->begin_frame_args.frame_id.sequence_number); + frame_args.frame_id.sequence_number); // This needs to run unconditionally, so do it before any early-returns. if (layer_tree_host_->scheduling_client()) @@ -156,6 +164,10 @@ void ProxyMain::BeginMainFrame( if (!layer_tree_host_->IsVisible()) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_WITH_FLOW1( + "viz,benchmark", "MainFrame.BeginMainFrameAbortedOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN, "reason", "ABORTED_NOT_VISIBLE"); // In this case, since the commit is deferred to a later time, gathered // events metrics are not discarded so that they can be reported if the // commit happens in the future. @@ -180,6 +192,11 @@ void ProxyMain::BeginMainFrame( if (defer_main_frame_update_) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_WITH_FLOW1("viz,benchmark", + "MainFrame.BeginMainFrameAbortedOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN, "reason", + "ABORTED_DEFERRED_MAIN_FRAME_UPDATE"); // In this case, since the commit is deferred to a later time, gathered // events metrics are not discarded so that they can be reported if the // commit happens in the future. @@ -243,12 +260,11 @@ void ProxyMain::BeginMainFrame( // See LayerTreeHostClient::BeginMainFrame for more documentation on // what this does. - layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args); + layer_tree_host_->BeginMainFrame(frame_args); // Updates cc animations on the main-thread. This is necessary in order // to track animation states such that they are cleaned up properly. - layer_tree_host_->AnimateLayers( - begin_main_frame_state->begin_frame_args.frame_time); + layer_tree_host_->AnimateLayers(frame_args.frame_time); // Recreates all UI resources if the compositor thread evicted UI resources // because it became invisible or there was a lost context when the compositor @@ -269,13 +285,17 @@ void ProxyMain::BeginMainFrame( // When we don't need to produce a CompositorFrame, there's also no need to // commit our updates. We still need to run layout and paint though, as it can // have side effects on page loading behavior. - skip_commit |= begin_main_frame_state->begin_frame_args.animate_only; + skip_commit |= frame_args.animate_only; if (skip_commit) { current_pipeline_stage_ = NO_PIPELINE_STAGE; layer_tree_host_->DidBeginMainFrame(); TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame", TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_WITH_FLOW1( + "viz,benchmark", "MainFrame.BeginMainFrameAbortedOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN, "reason", "ABORTED_DEFERRED_COMMIT"); layer_tree_host_->RecordEndOfFrameMetrics( begin_main_frame_start_time, begin_main_frame_state->active_sequence_trackers); @@ -324,8 +344,7 @@ void ProxyMain::BeginMainFrame( final_pipeline_stage_ = COMMIT_PIPELINE_STAGE; commit_trace_ = std::make_unique<devtools_instrumentation::ScopedCommitTrace>( - layer_tree_host_->GetId(), - begin_main_frame_state->begin_frame_args.frame_id.sequence_number); + layer_tree_host_->GetId(), frame_args.frame_id.sequence_number); auto completion_event_ptr = std::make_unique<CompletionEvent>( base::WaitableEvent::ResetPolicy::MANUAL); @@ -336,6 +355,12 @@ void ProxyMain::BeginMainFrame( std::unique_ptr<CommitState> commit_state = layer_tree_host_->WillCommit( std::move(completion_event_ptr), has_updates); DCHECK_EQ(has_updates, (bool)commit_state.get()); + if (commit_state.get()) { + commit_state->trace_id = + (0x1llu << 52) | // Signature bit chosen at random to avoid collisions + (frame_args.frame_id.source_id << 32) | + (commit_state->source_frame_number & 0xffffffff); + } current_pipeline_stage_ = COMMIT_PIPELINE_STAGE; if (!has_updates) { @@ -344,6 +369,10 @@ void ProxyMain::BeginMainFrame( layer_tree_host_->DidBeginMainFrame(); TRACE_EVENT_INSTANT0("cc,raf_investigation", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_WITH_FLOW1( + "viz,benchmark", "MainFrame.BeginMainFrameAbortedOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN, "reason", "FINISHED_NO_UPDATES"); std::vector<std::unique_ptr<SwapPromise>> swap_promises = layer_tree_host_->GetSwapPromiseManager()->TakeSwapPromises(); @@ -383,6 +412,15 @@ void ProxyMain::BeginMainFrame( CommitTimestamps commit_timestamps; bool blocking = !base::FeatureList::IsEnabled(features::kNonBlockingCommit); { + TRACE_EVENT_WITH_FLOW0("viz,benchmark", + "MainFrame.NotifyReadyToCommitOnMain", + TRACE_ID_LOCAL(begin_main_frame_state->trace_id), + TRACE_EVENT_FLAG_FLOW_IN); + TRACE_EVENT_WITH_FLOW0( + "viz,benchmark", "MainFrame.NotifyReadyToCommitOnMain", + TRACE_ID_LOCAL(commit_state->trace_id), TRACE_EVENT_FLAG_FLOW_OUT); + } + { TRACE_EVENT0("cc,raf_investigation", "ProxyMain::BeginMainFrame::commit"); absl::optional<DebugScopedSetMainThreadBlocked> main_thread_blocked; @@ -390,13 +428,13 @@ void ProxyMain::BeginMainFrame( main_thread_blocked.emplace(task_runner_provider_); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl, - base::Unretained(proxy_impl_.get()), - completion_event, std::move(commit_state), - &unsafe_state, begin_main_frame_start_time, - begin_main_frame_state->begin_frame_args, - blocking ? &commit_timestamps : nullptr, - commit_timeout)); + FROM_HERE, + base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl, + base::Unretained(proxy_impl_.get()), completion_event, + std::move(commit_state), &unsafe_state, + begin_main_frame_start_time, frame_args, + blocking ? &commit_timestamps : nullptr, + commit_timeout)); if (blocking) layer_tree_host_->WaitForProtectedSequenceCompletion(); } @@ -442,6 +480,11 @@ void ProxyMain::DidObserveFirstScrollDelay( first_scroll_timestamp); } +void ProxyMain::ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) { + layer_tree_host_->ReportEventLatency(std::move(latencies)); +} + bool ProxyMain::IsStarted() const { DCHECK(IsMainThread()); return started_; @@ -542,7 +585,7 @@ void ProxyMain::SetDeferMainFrameUpdate(bool defer_main_frame_update) { // The impl thread needs to know that it should not issue BeginMainFrame. ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::SetDeferBeginMainFrameOnImpl, + FROM_HERE, base::BindOnce(&ProxyImpl::SetDeferBeginMainFrameFromMain, base::Unretained(proxy_impl_.get()), defer_main_frame_update)); } @@ -760,14 +803,6 @@ void ProxyMain::SetRenderFrameObserver( base::Unretained(proxy_impl_.get()), std::move(observer))); } -void ProxyMain::SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) { - ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::SetEnableFrameRateThrottling, - base::Unretained(proxy_impl_.get()), - enable_frame_rate_throttling)); -} - uint32_t ProxyMain::GetAverageThroughput() const { NOTIMPLEMENTED(); return 0u; diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h index 79c20cae77d..1f0be862d15 100644 --- a/chromium/cc/trees/proxy_main.h +++ b/chromium/cc/trees/proxy_main.h @@ -12,6 +12,7 @@ #include "base/time/time.h" #include "cc/cc_export.h" #include "cc/input/browser_controls_state.h" +#include "cc/metrics/event_latency_tracker.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/paint_holding_reason.h" #include "cc/trees/proxy.h" @@ -71,6 +72,8 @@ class CC_EXPORT ProxyMain : public Proxy { void NotifyThroughputTrackerResults(CustomTrackerResults results); void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay, base::TimeTicks first_scroll_timestamp); + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies); CommitPipelineStage max_requested_pipeline_stage() const { return max_requested_pipeline_stage_; @@ -117,7 +120,6 @@ class CC_EXPORT ProxyMain : public Proxy { base::WritableSharedMemoryMapping ukm_smoothness_data) override; void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) override; - void SetEnableFrameRateThrottling(bool enable_frame_rate_throttling) override; uint32_t GetAverageThroughput() const override; // Returns |true| if the request was actually sent, |false| if one was diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc index 9e9e03db514..51add834b40 100644 --- a/chromium/cc/trees/render_frame_metadata.cc +++ b/chromium/cc/trees/render_frame_metadata.cc @@ -36,6 +36,10 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const { external_page_scale_factor == other.external_page_scale_factor && top_controls_height == other.top_controls_height && top_controls_shown_ratio == other.top_controls_shown_ratio && + previous_surfaces_visual_update_duration == + other.previous_surfaces_visual_update_duration && + current_surface_visual_update_duration == + other.current_surface_visual_update_duration && #if BUILDFLAG(IS_ANDROID) bottom_controls_height == other.bottom_controls_height && bottom_controls_shown_ratio == other.bottom_controls_shown_ratio && diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h index c83dd6b387c..0c0395e5eb5 100644 --- a/chromium/cc/trees/render_frame_metadata.h +++ b/chromium/cc/trees/render_frame_metadata.h @@ -5,6 +5,7 @@ #ifndef CC_TREES_RENDER_FRAME_METADATA_H_ #define CC_TREES_RENDER_FRAME_METADATA_H_ +#include "base/time/time.h" #include "build/build_config.h" #include "cc/cc_export.h" #include "components/viz/common/quads/selection.h" @@ -114,6 +115,14 @@ class CC_EXPORT RenderFrameMetadata { viz::VerticalScrollDirection new_vertical_scroll_direction = viz::VerticalScrollDirection::kNull; + // The cumulative time spent performing visual updates for all + // `local_surface_id` before this one. + base::TimeDelta previous_surfaces_visual_update_duration; + + // The cumulative time spent performing visual updates for the current + // `local_surface_id`. + base::TimeDelta current_surface_visual_update_duration; + #if BUILDFLAG(IS_ANDROID) // Used to position Android bottom bar, whose position is computed by the // renderer compositor. diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index c23b716f2da..0066ee64b58 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -230,39 +230,42 @@ void SingleThreadProxy::DoCommit(const viz::BeginFrameArgs& commit_args) { layer_tree_host_->GetId(), commit_args.frame_id.sequence_number); // Commit immediately. - { - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - DebugScopedSetImplThread impl(task_runner_provider_); + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); + DebugScopedSetImplThread impl(task_runner_provider_); - host_impl_->BeginCommit(commit_state->source_frame_number); + host_impl_->BeginCommit(commit_state->source_frame_number, + commit_state->trace_id); - host_impl_->FinishCommit(*commit_state, unsafe_state); - commit_state.reset(); - completion_event->Signal(); + host_impl_->FinishCommit(*commit_state, unsafe_state); + commit_state.reset(); + completion_event->Signal(); - if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->DidCommit(); + { + DebugScopedSetMainThread main(task_runner_provider_); + IssueImageDecodeFinishedCallbacks(); + } +} - { - DebugScopedSetMainThread main(task_runner_provider_); - IssueImageDecodeFinishedCallbacks(); - } - host_impl_->CommitComplete(); +void SingleThreadProxy::DoPostCommit() { + TRACE_EVENT0("cc", "SingleThreadProxy::DoPostCommit"); + DCHECK(task_runner_provider_->IsMainThread()); - std::vector<uint32_t> ids = - host_impl_->TakeFinishedTransitionRequestSequenceIds(); - { - DebugScopedSetMainThread main(task_runner_provider_); - layer_tree_host_->NotifyTransitionRequestsFinished(ids); - } + DebugScopedSetImplThread impl(task_runner_provider_); + host_impl_->CommitComplete(); - // Commit goes directly to the active tree, but we need to synchronously - // "activate" the tree still during commit to satisfy any potential - // SetNextCommitWaitsForActivation calls. Unfortunately, the tree - // might not be ready to draw, so DidActivateSyncTree must set - // the flag to force the tree to not draw until textures are ready. - NotifyReadyToActivate(); + std::vector<uint32_t> ids = + host_impl_->TakeFinishedTransitionRequestSequenceIds(); + { + DebugScopedSetMainThread main(task_runner_provider_); + layer_tree_host_->NotifyTransitionRequestsFinished(ids); } + + // Commit goes directly to the active tree, but we need to synchronously + // "activate" the tree still during commit to satisfy any potential + // SetNextCommitWaitsForActivation calls. Unfortunately, the tree + // might not be ready to draw, so DidActivateSyncTree must set + // the flag to force the tree to not draw until textures are ready. + NotifyReadyToActivate(); } void SingleThreadProxy::IssueImageDecodeFinishedCallbacks() { @@ -444,6 +447,13 @@ void SingleThreadProxy::NotifyReadyToActivate() { scheduler_on_impl_thread_->NotifyReadyToActivate(); } +bool SingleThreadProxy::IsReadyToActivate() { + DCHECK(!task_runner_provider_->HasImplThread() || + task_runner_provider_->IsImplThread()); + return scheduler_on_impl_thread_ && + scheduler_on_impl_thread_->IsReadyToActivate(); +} + void SingleThreadProxy::NotifyReadyToDraw() { DCHECK(!task_runner_provider_->HasImplThread() || task_runner_provider_->IsImplThread()); @@ -707,6 +717,7 @@ void SingleThreadProxy::CompositeImmediatelyForTest( base::AutoReset<bool> inside_composite(&inside_synchronous_composite_, true); if (layer_tree_frame_sink_lost_) { + auto sync = layer_tree_host_->ForceSyncCompositeForTest(); // IN-TEST RequestNewLayerTreeFrameSink(); // RequestNewLayerTreeFrameSink could have synchronously created an output // surface, so check again before returning. @@ -741,6 +752,7 @@ void SingleThreadProxy::CompositeImmediatelyForTest( commit_requested_ = false; DoPainting(begin_frame_args); DoCommit(begin_frame_args); + DoPostCommit(); DCHECK_EQ( 0u, @@ -882,6 +894,14 @@ size_t SingleThreadProxy::CommitDurationSampleCountForTesting() const { ->CommitDurationSampleCountForTesting(); // IN-TEST } +void SingleThreadProxy::ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) { + DCHECK(!task_runner_provider_->HasImplThread() || + task_runner_provider_->IsImplThread()); + DebugScopedSetMainThread main(task_runner_provider_); + layer_tree_host_->ReportEventLatency(std::move(latencies)); +} + void SingleThreadProxy::SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) { DCHECK(task_runner_provider_->IsMainThread()); @@ -889,11 +909,6 @@ void SingleThreadProxy::SetRenderFrameObserver( host_impl_->SetRenderFrameObserver(std::move(observer)); } -void SingleThreadProxy::SetEnableFrameRateThrottling( - bool enable_frame_rate_throttling) { - DCHECK(task_runner_provider_->IsMainThread()); -} - uint32_t SingleThreadProxy::GetAverageThroughput() const { DebugScopedSetImplThread impl(task_runner_provider_); return host_impl_->dropped_frame_counter()->GetAverageThroughput(); @@ -1114,6 +1129,14 @@ void SingleThreadProxy::ScheduledActionCommit() { DoCommit(scheduler_on_impl_thread_->last_dispatched_begin_main_frame_args()); } +void SingleThreadProxy::ScheduledActionPostCommit() { + // DebugScopedSetImplThread here is just a formality; all SchedulerClient + // methods should have it. + DebugScopedSetImplThread impl(task_runner_provider_); + DebugScopedSetMainThread main(task_runner_provider_); + DoPostCommit(); +} + void SingleThreadProxy::ScheduledActionActivateSyncTree() { DebugScopedSetImplThread impl(task_runner_provider_); host_impl_->ActivateSyncTree(); @@ -1130,6 +1153,7 @@ void SingleThreadProxy::ScheduledActionBeginLayerTreeFrameSinkCreation() { ScheduleRequestNewLayerTreeFrameSink(); } else { DebugScopedSetMainThread main(task_runner_provider_); + auto sync = layer_tree_host_->ForceSyncCompositeForTest(); // IN-TEST RequestNewLayerTreeFrameSink(); } } diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h index 76ed39ca284..fef5133be31 100644 --- a/chromium/cc/trees/single_thread_proxy.h +++ b/chromium/cc/trees/single_thread_proxy.h @@ -76,7 +76,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy, base::WritableSharedMemoryMapping ukm_smoothness_data) override; void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) override; - void SetEnableFrameRateThrottling(bool enable_frame_rate_throttling) override; uint32_t GetAverageThroughput() const override; void UpdateBrowserControlsState(BrowserControlsState constraints, @@ -95,6 +94,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, DrawResult ScheduledActionDrawIfPossible() override; DrawResult ScheduledActionDrawForced() override; void ScheduledActionCommit() override; + void ScheduledActionPostCommit() override; void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginLayerTreeFrameSinkCreation() override; void ScheduledActionPrepareTiles() override; @@ -112,12 +112,14 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void DidReceiveCompositorFrameAckOnImplThread() override; void OnCanDrawStateChanged(bool can_draw) override; void NotifyReadyToActivate() override; + bool IsReadyToActivate() override; void NotifyReadyToDraw() override; void SetNeedsRedrawOnImplThread() override; void SetNeedsOneBeginImplFrameOnImplThread() override; void SetNeedsPrepareTilesOnImplThread() override; void SetNeedsCommitOnImplThread() override; void SetVideoNeedsBeginFrames(bool needs_begin_frames) override; + void SetDeferBeginMainFrameFromImpl(bool defer_begin_main_frame) override {} bool IsInsideDraw() override; void RenewTreePriority() override; void PostDelayedAnimationTaskOnImplThread(base::OnceClosure task, @@ -145,6 +147,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy, const base::flat_set<viz::FrameSinkId>& ids) override; void ClearHistory() override; size_t CommitDurationSampleCountForTesting() const override; + void ReportEventLatency( + std::vector<EventLatencyTracker::LatencyData> latencies) override; void RequestNewLayerTreeFrameSink(); @@ -168,6 +172,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void DoBeginMainFrame(const viz::BeginFrameArgs& begin_frame_args); void DoPainting(const viz::BeginFrameArgs& commit_args); void DoCommit(const viz::BeginFrameArgs& commit_args); + void DoPostCommit(); DrawResult DoComposite(LayerTreeHostImpl::FrameData* frame); void DoSwap(); void DidCommitAndDrawFrame(); diff --git a/chromium/cc/trees/target_property.h b/chromium/cc/trees/target_property.h index a60b371119c..184e1b74a96 100644 --- a/chromium/cc/trees/target_property.h +++ b/chromium/cc/trees/target_property.h @@ -14,6 +14,9 @@ namespace TargetProperty { // Must be zero-based as this will be stored in a bitset. enum Type { TRANSFORM = 0, + SCALE, + ROTATE, + TRANSLATE, OPACITY, FILTER, SCROLL_OFFSET, diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h index b6177e0a92e..e3e7ca9f0d7 100644 --- a/chromium/cc/trees/transform_node.h +++ b/chromium/cc/trees/transform_node.h @@ -112,7 +112,8 @@ struct CC_EXPORT TransformNode { // visibility, not this transform one. bool delegates_to_parent_for_backface : 1; - // Set to true, if the compositing reason is will-change:transform. + // Set to true, if the compositing reason is will-change:transform, scale, + // rotate, or translate (for the CSS property that created this node). bool will_change_transform : 1; // Set to true, if the node or it's parent |will_change_transform| is true. diff --git a/chromium/cc/trees/ukm_manager.cc b/chromium/cc/trees/ukm_manager.cc index 2685122aaf0..6d8e8540aad 100644 --- a/chromium/cc/trees/ukm_manager.cc +++ b/chromium/cc/trees/ukm_manager.cc @@ -22,82 +22,12 @@ UkmManager::UkmManager(std::unique_ptr<ukm::UkmRecorder> recorder) DCHECK(recorder_); } -UkmManager::~UkmManager() { - RecordCheckerboardUkm(); - RecordRenderingUkm(); -} +UkmManager::~UkmManager() = default; void UkmManager::SetSourceId(ukm::SourceId source_id) { - // If we accumulated any metrics, record them before resetting the source. - RecordCheckerboardUkm(); - RecordRenderingUkm(); - source_id_ = source_id; } -void UkmManager::SetUserInteractionInProgress(bool in_progress) { - if (user_interaction_in_progress_ == in_progress) - return; - - user_interaction_in_progress_ = in_progress; - if (!user_interaction_in_progress_) - RecordCheckerboardUkm(); -} - -void UkmManager::AddCheckerboardStatsForFrame(int64_t checkerboard_area, - int64_t num_missing_tiles, - int64_t total_visible_area) { - DCHECK_GE(total_visible_area, checkerboard_area); - if (source_id_ == ukm::kInvalidSourceId || !user_interaction_in_progress_) - return; - - checkerboarded_content_area_ += checkerboard_area; - num_missing_tiles_ += num_missing_tiles; - total_visible_area_ += total_visible_area; - num_of_frames_++; -} - -void UkmManager::AddCheckerboardedImages(int num_of_checkerboarded_images) { - if (user_interaction_in_progress_) { - num_of_images_checkerboarded_during_interaction_ += - num_of_checkerboarded_images; - } - total_num_of_checkerboarded_images_ += num_of_checkerboarded_images; -} - -void UkmManager::RecordCheckerboardUkm() { - // Only make a recording if there was any visible area from PictureLayers, - // which can be checkerboarded. - if (num_of_frames_ > 0 && total_visible_area_ > 0) { - DCHECK_NE(source_id_, ukm::kInvalidSourceId); - ukm::builders::Compositor_UserInteraction(source_id_) - .SetCheckerboardedContentArea(checkerboarded_content_area_ / - num_of_frames_) - .SetNumMissingTiles(num_missing_tiles_ / num_of_frames_) - .SetCheckerboardedContentAreaRatio( - (checkerboarded_content_area_ * 100) / total_visible_area_) - .SetCheckerboardedImagesCount( - num_of_images_checkerboarded_during_interaction_) - .Record(recorder_.get()); - } - - checkerboarded_content_area_ = 0; - num_missing_tiles_ = 0; - num_of_frames_ = 0; - total_visible_area_ = 0; - num_of_images_checkerboarded_during_interaction_ = 0; -} - -void UkmManager::RecordRenderingUkm() { - if (source_id_ == ukm::kInvalidSourceId) - return; - - ukm::builders::Compositor_Rendering(source_id_) - .SetCheckerboardedImagesCount(total_num_of_checkerboarded_images_) - .Record(recorder_.get()); - total_num_of_checkerboarded_images_ = 0; -} - void UkmManager::RecordThroughputUKM( FrameSequenceTrackerType tracker_type, FrameInfo::SmoothEffectDrivingThread thread_type, @@ -121,7 +51,11 @@ void UkmManager::RecordThroughputUKM( CASE_FOR_MAIN_THREAD_TRACKER(CanvasAnimation); CASE_FOR_MAIN_THREAD_TRACKER(JSAnimation); #undef CASE_FOR_MAIN_THREAD_TRACKER - default: + case FrameSequenceTrackerType::kSETCompositorAnimation: + case FrameSequenceTrackerType::kSETMainThreadAnimation: + break; + case FrameSequenceTrackerType::kCustom: + case FrameSequenceTrackerType::kMaxType: NOTREACHED(); break; } @@ -144,7 +78,13 @@ void UkmManager::RecordThroughputUKM( CASE_FOR_COMPOSITOR_THREAD_TRACKER(Video); CASE_FOR_COMPOSITOR_THREAD_TRACKER(WheelScroll); #undef CASE_FOR_COMPOSITOR_THREAD_TRACKER - default: + case FrameSequenceTrackerType::kCanvasAnimation: + case FrameSequenceTrackerType::kJSAnimation: + case FrameSequenceTrackerType::kSETCompositorAnimation: + case FrameSequenceTrackerType::kSETMainThreadAnimation: + break; + case FrameSequenceTrackerType::kCustom: + case FrameSequenceTrackerType::kMaxType: NOTREACHED(); break; } @@ -208,7 +148,7 @@ void UkmManager::RecordCompositorLatencyUKM( CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame); CASE_FOR_STAGE(TotalLatency); #undef CASE_FOR_STAGE - default: + case StageType::kStageTypeCount: NOTREACHED(); break; } @@ -227,6 +167,7 @@ void UkmManager::RecordCompositorLatencyUKM( CASE_FOR_BLINK_BREAKDOWN(Animate); CASE_FOR_BLINK_BREAKDOWN(StyleUpdate); CASE_FOR_BLINK_BREAKDOWN(LayoutUpdate); + CASE_FOR_BLINK_BREAKDOWN(Accessibility); CASE_FOR_BLINK_BREAKDOWN(Prepaint); CASE_FOR_BLINK_BREAKDOWN(CompositingInputs); CASE_FOR_BLINK_BREAKDOWN(Paint); @@ -234,7 +175,7 @@ void UkmManager::RecordCompositorLatencyUKM( CASE_FOR_BLINK_BREAKDOWN(UpdateLayers); CASE_FOR_BLINK_BREAKDOWN(BeginMainSentToStarted); #undef CASE_FOR_BLINK_BREAKDOWN - default: + case CompositorFrameReporter::BlinkBreakdown::kBreakdownCount: NOTREACHED(); break; } @@ -259,7 +200,7 @@ void UkmManager::RecordCompositorLatencyUKM( CASE_FOR_VIZ_BREAKDOWN(BufferReadyToLatch); CASE_FOR_VIZ_BREAKDOWN(LatchToSwapEnd); #undef CASE_FOR_VIZ_BREAKDOWN - default: + case CompositorFrameReporter::VizBreakdown::kBreakdownCount: NOTREACHED(); break; } @@ -287,7 +228,11 @@ void UkmManager::RecordCompositorLatencyUKM( CASE_FOR_TRACKER(CanvasAnimation); CASE_FOR_TRACKER(JSAnimation); #undef CASE_FOR_TRACKER - default: + case FrameSequenceTrackerType::kSETCompositorAnimation: + case FrameSequenceTrackerType::kSETMainThreadAnimation: + break; + case FrameSequenceTrackerType::kCustom: + case FrameSequenceTrackerType::kMaxType: NOTREACHED(); break; } @@ -397,15 +342,13 @@ void UkmManager::RecordEventLatencyUKM( auto stage_it = std::find_if( stage_history.begin(), stage_history.end(), [dispatch_timestamp](const CompositorFrameReporter::StageData& stage) { - return stage.start_time > dispatch_timestamp; + return stage.start_time >= dispatch_timestamp; }); - // TODO(crbug.com/1079116): Ideally, at least the start time of + // TODO(crbug.com/1330903): Ideally, at least the start time of // SubmitCompositorFrameToPresentationCompositorFrame stage should be - // greater than the final event dispatch timestamp, but apparently, this is - // not always the case (see crbug.com/1093698). For now, skip to the next - // event in such cases. Hopefully, the work to reduce discrepancies between - // the new EventLatency and the old Event.Latency metrics would fix this - // issue. If not, we need to reconsider investigating this issue. + // greater than or equal to the final event dispatch timestamp, but + // apparently, this is not always the case (see crbug.com/1330903). Skip + // recording compositor stages for now until we investigate the issue. if (stage_it == stage_history.end()) continue; @@ -426,7 +369,8 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame, SubmitCompositorFrame); #undef CASE_FOR_STAGE - default: + case StageType::kTotalLatency: + case StageType::kStageTypeCount: NOTREACHED(); break; } @@ -447,7 +391,8 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame, SubmitCompositorFrame); #undef CASE_FOR_STAGE - default: + case StageType::kTotalLatency: + case StageType::kStageTypeCount: NOTREACHED(); break; } @@ -456,7 +401,6 @@ void UkmManager::RecordEventLatencyUKM( NOTREACHED(); break; } - for (; stage_it != stage_history.end(); ++stage_it) { // Total latency is calculated since the event timestamp. const base::TimeTicks start_time = @@ -478,7 +422,7 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame); CASE_FOR_STAGE(TotalLatency); #undef CASE_FOR_STAGE - default: + case StageType::kStageTypeCount: NOTREACHED(); break; } @@ -497,6 +441,7 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_BLINK_BREAKDOWN(Animate); CASE_FOR_BLINK_BREAKDOWN(StyleUpdate); CASE_FOR_BLINK_BREAKDOWN(LayoutUpdate); + CASE_FOR_BLINK_BREAKDOWN(Accessibility); CASE_FOR_BLINK_BREAKDOWN(Prepaint); CASE_FOR_BLINK_BREAKDOWN(CompositingInputs); CASE_FOR_BLINK_BREAKDOWN(Paint); @@ -504,7 +449,7 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_BLINK_BREAKDOWN(UpdateLayers); CASE_FOR_BLINK_BREAKDOWN(BeginMainSentToStarted); #undef CASE_FOR_BLINK_BREAKDOWN - default: + case CompositorFrameReporter::BlinkBreakdown::kBreakdownCount: NOTREACHED(); break; } @@ -529,7 +474,7 @@ void UkmManager::RecordEventLatencyUKM( CASE_FOR_VIZ_BREAKDOWN(BufferReadyToLatch); CASE_FOR_VIZ_BREAKDOWN(LatchToSwapEnd); #undef CASE_FOR_VIZ_BREAKDOWN - default: + case CompositorFrameReporter::VizBreakdown::kBreakdownCount: NOTREACHED(); break; } diff --git a/chromium/cc/trees/ukm_manager.h b/chromium/cc/trees/ukm_manager.h index 1345e2482f1..1c0a157c036 100644 --- a/chromium/cc/trees/ukm_manager.h +++ b/chromium/cc/trees/ukm_manager.h @@ -38,15 +38,6 @@ class CC_EXPORT UkmManager { void SetSourceId(ukm::SourceId source_id); - // These metrics are recorded while a user interaction is in progress. - void SetUserInteractionInProgress(bool in_progress); - void AddCheckerboardStatsForFrame(int64_t checkerboard_area, - int64_t num_missing_tiles, - int64_t total_visible_area); - - // These metrics are recorded until the source URL changes. - void AddCheckerboardedImages(int num_of_checkerboarded_images); - void RecordThroughputUKM(FrameSequenceTrackerType tracker_type, FrameInfo::SmoothEffectDrivingThread thread_type, int64_t throughput) const; @@ -72,18 +63,6 @@ class CC_EXPORT UkmManager { ukm::UkmRecorder* recorder_for_testing() { return recorder_.get(); } private: - void RecordCheckerboardUkm(); - void RecordRenderingUkm(); - - bool user_interaction_in_progress_ = false; - int64_t num_of_images_checkerboarded_during_interaction_ = 0; - int64_t checkerboarded_content_area_ = 0; - int64_t num_missing_tiles_ = 0; - int64_t total_visible_area_ = 0; - int64_t num_of_frames_ = 0; - - int total_num_of_checkerboarded_images_ = 0; - ukm::SourceId source_id_ = ukm::kInvalidSourceId; std::unique_ptr<ukm::UkmRecorder> recorder_; }; diff --git a/chromium/cc/trees/ukm_manager_unittest.cc b/chromium/cc/trees/ukm_manager_unittest.cc index 2fa9afde6da..abb3a9bdbb5 100644 --- a/chromium/cc/trees/ukm_manager_unittest.cc +++ b/chromium/cc/trees/ukm_manager_unittest.cc @@ -25,15 +25,6 @@ namespace { 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"; - -const char kCheckerboardArea[] = "CheckerboardedContentArea"; -const char kCheckerboardAreaRatio[] = "CheckerboardedContentAreaRatio"; -const char kMissingTiles[] = "NumMissingTiles"; -const char kCheckerboardedImagesCount[] = "CheckerboardedImagesCount"; // Names of compositor/event latency UKM events. const char kCompositorLatency[] = "Graphics.Smoothness.Latency"; @@ -244,64 +235,6 @@ class UkmManagerTest : public testing::Test { base::SimpleTestTickClock test_tick_clock_; }; -TEST_F(UkmManagerTest, Basic) { - manager_->SetUserInteractionInProgress(true); - manager_->AddCheckerboardStatsForFrame(5, 1, 10); - manager_->AddCheckerboardStatsForFrame(15, 3, 30); - manager_->AddCheckerboardedImages(6); - manager_->SetUserInteractionInProgress(false); - - // We should see a single entry for the interaction above. - const auto& entries = test_ukm_recorder_->GetEntriesByName(kUserInteraction); - ukm::SourceId original_id = ukm::kInvalidSourceId; - EXPECT_EQ(1u, entries.size()); - for (const auto* entry : entries) { - original_id = entry->source_id; - EXPECT_NE(ukm::kInvalidSourceId, entry->source_id); - 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); - test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 6); - } - test_ukm_recorder_->Purge(); - - // Try pushing some stats while no user interaction is happening. No entries - // should be pushed. - manager_->AddCheckerboardStatsForFrame(6, 1, 10); - manager_->AddCheckerboardStatsForFrame(99, 3, 100); - EXPECT_EQ(0u, test_ukm_recorder_->entries_count()); - manager_->SetUserInteractionInProgress(true); - EXPECT_EQ(0u, test_ukm_recorder_->entries_count()); - - // Record a few entries and change the source before the interaction ends. The - // stats collected up till this point should be recorded before the source is - // swapped. - manager_->AddCheckerboardStatsForFrame(10, 1, 100); - manager_->AddCheckerboardStatsForFrame(30, 5, 100); - - manager_->SetSourceId(kTestSourceId2); - - const auto& entries2 = test_ukm_recorder_->GetEntriesByName(kUserInteraction); - EXPECT_EQ(1u, entries2.size()); - for (const auto* entry : entries2) { - EXPECT_EQ(original_id, entry->source_id); - test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardArea, 20); - test_ukm_recorder_->ExpectEntryMetric(entry, kMissingTiles, 3); - test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 20); - test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 0); - } - - // An entry for rendering is emitted when the URL changes. - const auto& entries_rendering = - test_ukm_recorder_->GetEntriesByName(kRendering); - EXPECT_EQ(1u, entries_rendering.size()); - for (const auto* entry : entries_rendering) { - EXPECT_EQ(original_id, entry->source_id); - test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardedImagesCount, 6); - } -} - class UkmManagerCompositorLatencyTest : public UkmManagerTest, public testing::WithParamInterface< |