diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 15:05:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:33:47 +0000 |
commit | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch) | |
tree | d55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/cc | |
parent | 2b94bfe47ccb6c08047959d1c26e392919550e86 (diff) |
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/cc')
248 files changed, 5371 insertions, 3249 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn index b5a24d07eca..1c7b04e7a28 100644 --- a/chromium/cc/BUILD.gn +++ b/chromium/cc/BUILD.gn @@ -54,6 +54,8 @@ cc_component("cc") { "input/snap_fling_controller.h", "input/snap_fling_curve.cc", "input/snap_fling_curve.h", + "input/snap_selection_strategy.cc", + "input/snap_selection_strategy.h", "input/touch_action.h", "layers/append_quads_data.cc", "layers/append_quads_data.h", @@ -295,6 +297,7 @@ cc_component("cc") { "trees/layer_tree_impl.h", "trees/layer_tree_mutator.cc", "trees/layer_tree_mutator.h", + "trees/layer_tree_painter.h", "trees/layer_tree_settings.cc", "trees/layer_tree_settings.h", "trees/managed_memory_policy.cc", @@ -360,7 +363,6 @@ cc_component("cc") { "//gpu", "//gpu/command_buffer/client:gles2_interface", "//gpu/command_buffer/client:raster_interface", - "//gpu/ipc:gl_in_process_context", "//gpu/skia_bindings:skia_bindings", "//gpu/vulkan:buildflags", "//media", # For VideoLayerImpl. @@ -611,6 +613,7 @@ cc_test("cc_unittests") { "paint/display_item_list_unittest.cc", "paint/filter_operations_unittest.cc", "paint/oop_pixeltest.cc", + "paint/paint_cache_unittest.cc", "paint/paint_filter_unittest.cc", "paint/paint_image_unittest.cc", "paint/paint_op_buffer_unittest.cc", diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS index 5a453bed667..10a074fa7f1 100644 --- a/chromium/cc/OWNERS +++ b/chromium/cc/OWNERS @@ -58,6 +58,7 @@ vmpstr@chromium.org # surfaces fsamuel@chromium.org kylechar@chromium.org +samans@chromium.org # input, scrolling bokan@chromium.org diff --git a/chromium/cc/PRESUBMIT.py b/chromium/cc/PRESUBMIT.py index 3e27d70855f..89f5675b100 100644 --- a/chromium/cc/PRESUBMIT.py +++ b/chromium/cc/PRESUBMIT.py @@ -287,17 +287,3 @@ def CheckChangeOnUpload(input_api, output_api): results += CheckForUseOfWrongClock(input_api, output_api) results += FindUselessIfdefs(input_api, output_api) return results - -def PostUploadHook(cl, change, output_api): - """git cl upload will call this hook after the issue is created/modified. - - This hook adds an extra try bot list to the CL description in order to run - Blink tests and additional GPU tests in addition to the CQ try bots. - """ - return output_api.EnsureCQIncludeTrybotsAreAdded( - cl, - [ - 'master.tryserver.blink:linux_trusty_blink_rel', - 'luci.chromium.try:android_optional_gpu_tests_rel', - ], - 'Automatically added Blink and Android GPU trybots for CQ.') diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc index 696e69e8e9b..b78c578afd6 100644 --- a/chromium/cc/animation/animation_host.cc +++ b/chromium/cc/animation/animation_host.cc @@ -12,7 +12,7 @@ #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/animation/animation.h" #include "cc/animation/animation_delegate.h" #include "cc/animation/animation_events.h" diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc index 104b16c7843..f4fd4805933 100644 --- a/chromium/cc/animation/animation_host_unittest.cc +++ b/chromium/cc/animation/animation_host_unittest.cc @@ -50,7 +50,8 @@ class AnimationHostTest : public AnimationTimelinesTest { } void SetOutputState(base::TimeDelta local_time) { - MutatorOutputState::AnimationState state(worklet_animation_id_, local_time); + MutatorOutputState::AnimationState state(worklet_animation_id_); + state.local_times.push_back(local_time); worklet_animation_impl_->SetOutputState(state); } @@ -262,7 +263,7 @@ void CreateScrollingNodeForElement(ElementId element_id, // A scrolling node in cc has a corresponding transform node (See // |ScrollNode::transform_id|). This setup here creates both nodes and links // them as they would normally be. This more complete setup is necessary here - // because ScrollTimelin depends on both nodes for its calculations. + // because ScrollTimeline depends on both nodes for its calculations. TransformNode transform_node; transform_node.scrolls = true; transform_node.source_node_id = TransformTree::kRootNodeId; @@ -327,8 +328,9 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) { // Create scroll timeline that links scroll animation and worklet animation // together. Use timerange so that we have 1:1 time & scroll mapping. - auto scroll_timeline = std::make_unique<ScrollTimeline>( - element_id, ScrollTimeline::Vertical, 100); + auto scroll_timeline = + std::make_unique<ScrollTimeline>(element_id, ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100); // Create a worklet animation that is bound to the scroll timeline. scoped_refptr<WorkletAnimation> worklet_animation( diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc index 2af7060976c..f5d216cd5ab 100644 --- a/chromium/cc/animation/element_animations.cc +++ b/chromium/cc/animation/element_animations.cc @@ -22,6 +22,22 @@ namespace cc { +namespace { + +// After BlinkGenPropertyTrees, the targeted ElementId depends on the property +// being mutated. If an ElementId is set on the KeyframeModel, we should apply +// the mutation to the specific element. +// TODO(flackr): Remove ElementId from ElementAnimations once all element +// tracking is done on the KeyframeModel - https://crbug.com/900241 +ElementId CalculateTargetElementId(const ElementAnimations* element_animations, + const KeyframeModel* keyframe_model) { + if (keyframe_model->element_id()) + return keyframe_model->element_id(); + return element_animations->element_id(); +} + +} // namespace + scoped_refptr<ElementAnimations> ElementAnimations::Create() { return base::WrapRefCounted(new ElementAnimations()); } @@ -262,9 +278,9 @@ void ElementAnimations::NotifyClientFloatAnimated( DCHECK(keyframe_model->target_property_id() == TargetProperty::OPACITY); opacity = base::ClampToRange(opacity, 0.0f, 1.0f); if (KeyframeModelAffectsActiveElements(keyframe_model)) - OnOpacityAnimated(ElementListType::ACTIVE, opacity); + OnOpacityAnimated(ElementListType::ACTIVE, opacity, keyframe_model); if (KeyframeModelAffectsPendingElements(keyframe_model)) - OnOpacityAnimated(ElementListType::PENDING, opacity); + OnOpacityAnimated(ElementListType::PENDING, opacity, keyframe_model); } void ElementAnimations::NotifyClientFilterAnimated( @@ -272,9 +288,9 @@ void ElementAnimations::NotifyClientFilterAnimated( int target_property_id, KeyframeModel* keyframe_model) { if (KeyframeModelAffectsActiveElements(keyframe_model)) - OnFilterAnimated(ElementListType::ACTIVE, filters); + OnFilterAnimated(ElementListType::ACTIVE, filters, keyframe_model); if (KeyframeModelAffectsPendingElements(keyframe_model)) - OnFilterAnimated(ElementListType::PENDING, filters); + OnFilterAnimated(ElementListType::PENDING, filters, keyframe_model); } void ElementAnimations::NotifyClientTransformOperationsAnimated( @@ -283,9 +299,9 @@ void ElementAnimations::NotifyClientTransformOperationsAnimated( KeyframeModel* keyframe_model) { gfx::Transform transform = operations.Apply(); if (KeyframeModelAffectsActiveElements(keyframe_model)) - OnTransformAnimated(ElementListType::ACTIVE, transform); + OnTransformAnimated(ElementListType::ACTIVE, transform, keyframe_model); if (KeyframeModelAffectsPendingElements(keyframe_model)) - OnTransformAnimated(ElementListType::PENDING, transform); + OnTransformAnimated(ElementListType::PENDING, transform, keyframe_model); } void ElementAnimations::NotifyClientScrollOffsetAnimated( @@ -293,9 +309,11 @@ void ElementAnimations::NotifyClientScrollOffsetAnimated( int target_property_id, KeyframeModel* keyframe_model) { if (KeyframeModelAffectsActiveElements(keyframe_model)) - OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset); + OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset, + keyframe_model); if (KeyframeModelAffectsPendingElements(keyframe_model)) - OnScrollOffsetAnimated(ElementListType::PENDING, scroll_offset); + OnScrollOffsetAnimated(ElementListType::PENDING, scroll_offset, + keyframe_model); } void ElementAnimations::UpdateClientAnimationState() { @@ -395,40 +413,48 @@ bool ElementAnimations::IsCurrentlyAnimatingProperty( } void ElementAnimations::OnFilterAnimated(ElementListType list_type, - const FilterOperations& filters) { - DCHECK(element_id()); + const FilterOperations& filters, + KeyframeModel* keyframe_model) { + ElementId target_element_id = CalculateTargetElementId(this, keyframe_model); + DCHECK(target_element_id); DCHECK(animation_host()); DCHECK(animation_host()->mutator_host_client()); animation_host()->mutator_host_client()->SetElementFilterMutated( - element_id(), list_type, filters); + target_element_id, list_type, filters); } void ElementAnimations::OnOpacityAnimated(ElementListType list_type, - float opacity) { - DCHECK(element_id()); + float opacity, + KeyframeModel* keyframe_model) { + ElementId target_element_id = CalculateTargetElementId(this, keyframe_model); + DCHECK(target_element_id); DCHECK(animation_host()); DCHECK(animation_host()->mutator_host_client()); animation_host()->mutator_host_client()->SetElementOpacityMutated( - element_id(), list_type, opacity); + target_element_id, list_type, opacity); } void ElementAnimations::OnTransformAnimated(ElementListType list_type, - const gfx::Transform& transform) { - DCHECK(element_id()); + const gfx::Transform& transform, + KeyframeModel* keyframe_model) { + ElementId target_element_id = CalculateTargetElementId(this, keyframe_model); + DCHECK(target_element_id); DCHECK(animation_host()); DCHECK(animation_host()->mutator_host_client()); animation_host()->mutator_host_client()->SetElementTransformMutated( - element_id(), list_type, transform); + target_element_id, list_type, transform); } void ElementAnimations::OnScrollOffsetAnimated( ElementListType list_type, - const gfx::ScrollOffset& scroll_offset) { - DCHECK(element_id()); + const gfx::ScrollOffset& scroll_offset, + KeyframeModel* keyframe_model) { + ElementId target_element_id = CalculateTargetElementId(this, keyframe_model); + DCHECK(target_element_id); DCHECK(animation_host()); DCHECK(animation_host()->mutator_host_client()); animation_host()->mutator_host_client()->SetElementScrollOffsetMutated( - element_id(), list_type, scroll_offset); + target_element_id, list_type, scroll_offset); } gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const { diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h index c7e68bbec14..7c51dc7900f 100644 --- a/chromium/cc/animation/element_animations.h +++ b/chromium/cc/animation/element_animations.h @@ -171,12 +171,17 @@ class CC_ANIMATION_EXPORT ElementAnimations ~ElementAnimations() override; void OnFilterAnimated(ElementListType list_type, - const FilterOperations& filters); - void OnOpacityAnimated(ElementListType list_type, float opacity); + const FilterOperations& filters, + KeyframeModel* keyframe_model); + void OnOpacityAnimated(ElementListType list_type, + float opacity, + KeyframeModel* keyframe_model); void OnTransformAnimated(ElementListType list_type, - const gfx::Transform& transform); + const gfx::Transform& transform, + KeyframeModel* keyframe_model); void OnScrollOffsetAnimated(ElementListType list_type, - const gfx::ScrollOffset& scroll_offset); + const gfx::ScrollOffset& scroll_offset, + KeyframeModel* keyframe_model); static TargetProperties GetPropertiesMaskForAnimationState(); diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h index 0c33cb7db6d..a276b7d00e5 100644 --- a/chromium/cc/animation/keyframe_effect.h +++ b/chromium/cc/animation/keyframe_effect.h @@ -27,8 +27,8 @@ struct PropertyAnimationState; typedef size_t KeyframeEffectId; -// An KeyframeEffect owns a group of KeyframeModels for a single target -// (identified by a ElementId). It is responsible for managing the +// A KeyframeEffect owns a group of KeyframeModels for a single target +// (identified by an ElementId). It is responsible for managing the // KeyframeModels' running states (starting, running, paused, etc), as well as // ticking the KeyframeModels when it is requested to produce new outputs for a // given time. diff --git a/chromium/cc/animation/keyframe_model.cc b/chromium/cc/animation/keyframe_model.cc index 10556098fc8..13b2f100cd1 100644 --- a/chromium/cc/animation/keyframe_model.cc +++ b/chromium/cc/animation/keyframe_model.cc @@ -61,6 +61,7 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance( DCHECK(!is_controlling_instance_); std::unique_ptr<KeyframeModel> to_return( new KeyframeModel(curve_->Clone(), id_, group_, target_property_id_)); + to_return->element_id_ = element_id_; to_return->run_state_ = initial_run_state; to_return->iterations_ = iterations_; to_return->iteration_start_ = iteration_start_; @@ -263,8 +264,7 @@ base::TimeDelta KeyframeModel::TrimLocalTimeToCurrentIteration( } void KeyframeModel::PushPropertiesTo(KeyframeModel* other) const { - // Currently, we only push changes due to pausing and resuming KeyframeModels - // on the main thread. + other->element_id_ = element_id_; if (run_state_ == KeyframeModel::PAUSED || other->run_state_ == KeyframeModel::PAUSED) { other->run_state_ = run_state_; diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h index 329a986253f..39557caa3e4 100644 --- a/chromium/cc/animation/keyframe_model.h +++ b/chromium/cc/animation/keyframe_model.h @@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "cc/animation/animation_export.h" +#include "cc/trees/element_id.h" namespace cc { @@ -69,6 +70,9 @@ class CC_ANIMATION_EXPORT KeyframeModel { int group() const { return group_; } int target_property_id() const { return target_property_id_; } + ElementId element_id() const { return element_id_; } + void set_element_id(ElementId element_id) { element_id_ = element_id; } + RunState run_state() const { return run_state_; } void SetRunState(RunState run_state, base::TimeTicks monotonic_time); @@ -212,6 +216,10 @@ class CC_ANIMATION_EXPORT KeyframeModel { // properties until all KeyframeModels in the group have finished animating. int group_; + // If specified, overrides the ElementId to apply this KeyframeModel's effect + // value on. + ElementId element_id_; + int target_property_id_; RunState run_state_; double iterations_; diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc index 7c11c2d5281..ec4bafbd264 100644 --- a/chromium/cc/animation/scroll_offset_animations_impl.cc +++ b/chromium/cc/animation/scroll_offset_animations_impl.cc @@ -5,7 +5,7 @@ #include "cc/animation/scroll_offset_animations_impl.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/animation/animation_host.h" #include "cc/animation/animation_id_provider.h" #include "cc/animation/animation_timeline.h" diff --git a/chromium/cc/animation/scroll_timeline.cc b/chromium/cc/animation/scroll_timeline.cc index 63a56ec8584..14cfc971219 100644 --- a/chromium/cc/animation/scroll_timeline.cc +++ b/chromium/cc/animation/scroll_timeline.cc @@ -11,19 +11,36 @@ namespace cc { +namespace { +bool IsVertical(ScrollTimeline::ScrollDirection direction) { + return direction == ScrollTimeline::ScrollUp || + direction == ScrollTimeline::ScrollDown; +} + +bool IsReverse(ScrollTimeline::ScrollDirection direction) { + return direction == ScrollTimeline::ScrollUp || + direction == ScrollTimeline::ScrollLeft; +} +} // namespace + ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id, - ScrollDirection orientation, + ScrollDirection direction, + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset, double time_range) : active_id_(), pending_id_(scroller_id), - orientation_(orientation), + direction_(direction), + start_scroll_offset_(start_scroll_offset), + end_scroll_offset_(end_scroll_offset), time_range_(time_range) {} ScrollTimeline::~ScrollTimeline() {} std::unique_ptr<ScrollTimeline> ScrollTimeline::CreateImplInstance() const { - return std::make_unique<ScrollTimeline>(pending_id_, orientation_, - time_range_); + return std::make_unique<ScrollTimeline>(pending_id_, direction_, + start_scroll_offset_, + end_scroll_offset_, time_range_); } double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree, @@ -53,35 +70,76 @@ double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree, gfx::ScrollOffset scroll_dimensions = scroll_tree.MaxScrollOffset(scroll_node->id); - double current_offset = (orientation_ == Vertical) ? offset.y() : offset.x(); - double max_offset = (orientation_ == Vertical) ? scroll_dimensions.y() - : scroll_dimensions.x(); + double max_offset = + IsVertical(direction_) ? scroll_dimensions.y() : scroll_dimensions.x(); + double current_physical_offset = + IsVertical(direction_) ? offset.y() : offset.x(); + double current_offset = IsReverse(direction_) + ? max_offset - current_physical_offset + : current_physical_offset; + DCHECK_GE(max_offset, 0); + DCHECK_GE(current_offset, 0); + + double resolved_start_scroll_offset = start_scroll_offset_.value_or(0); + double resolved_end_scroll_offset = end_scroll_offset_.value_or(max_offset); // 3. If current scroll offset is less than startScrollOffset, return an // unresolved time value if fill is none or forwards, or 0 otherwise. - // TODO(smcgruer): Implement |startScrollOffset| and |fill|. + // TODO(smcgruer): Implement |fill|. + if (current_offset < resolved_start_scroll_offset) { + return std::numeric_limits<double>::quiet_NaN(); + } // 4. If current scroll offset is greater than or equal to endScrollOffset, // return an unresolved time value if fill is none or backwards, or the // effective time range otherwise. - // TODO(smcgruer): Implement |endScrollOffset| and |fill|. + // TODO(smcgruer): Implement |fill|. + // + // Note we deliberately break the spec here by only returning if the current + // offset is strictly greater, as that is more in line with the web animation + // spec. See https://github.com/WICG/scroll-animations/issues/19 + if (current_offset > resolved_end_scroll_offset) { + return std::numeric_limits<double>::quiet_NaN(); + } + + // This is not by the spec, but avoids both negative current time and a + // division by zero issue. See + // https://github.com/WICG/scroll-animations/issues/20 and + // https://github.com/WICG/scroll-animations/issues/21 + if (resolved_start_scroll_offset >= resolved_end_scroll_offset) { + return std::numeric_limits<double>::quiet_NaN(); + } // 5. Return the result of evaluating the following expression: // ((current scroll offset - startScrollOffset) / // (endScrollOffset - startScrollOffset)) * effective time range - - return (std::abs(current_offset) / max_offset) * time_range_; + return ((current_offset - resolved_start_scroll_offset) / + (resolved_end_scroll_offset - resolved_start_scroll_offset)) * + time_range_; } void ScrollTimeline::PushPropertiesTo(ScrollTimeline* impl_timeline) { DCHECK(impl_timeline); impl_timeline->pending_id_ = pending_id_; + // TODO(smcgruer): This leads to incorrect behavior in the current design, + // because we end up using the pending start/end scroll offset for the active + // tree too. Instead we need to either split these (like pending_id_ and + // active_id_) or have a ScrollTimeline per tree. + impl_timeline->start_scroll_offset_ = start_scroll_offset_; + impl_timeline->end_scroll_offset_ = end_scroll_offset_; } void ScrollTimeline::PromoteScrollTimelinePendingToActive() { active_id_ = pending_id_; } +void ScrollTimeline::UpdateStartAndEndScrollOffsets( + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset) { + start_scroll_offset_ = start_scroll_offset; + end_scroll_offset_ = end_scroll_offset; +} + void ScrollTimeline::SetScrollerId(base::Optional<ElementId> pending_id) { // When the scroller id changes it will first be modified in the pending tree. // Then later (when the pending tree is promoted to active) diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h index 1efd2a77963..c1a1dc34d76 100644 --- a/chromium/cc/animation/scroll_timeline.h +++ b/chromium/cc/animation/scroll_timeline.h @@ -17,18 +17,20 @@ class ScrollTree; // progress of scrolling in some scroll container. // // This is the compositor-side representation of the web concept expressed in -// https://wicg.github.io/scroll-animations/#scrolltimeline-interface. There are -// differences between this class and the web definition of a ScrollTimeline. -// For example the compositor does not know (or care) about 'writing modes', so -// this class only tracks whether the ScrollTimeline orientation is horizontal -// or vertical. Blink is expected to resolve any such 'web' requirements and -// construct/update the compositor ScrollTimeline accordingly. +// https://wicg.github.io/scroll-animations/#scrolltimeline-interface. class CC_ANIMATION_EXPORT ScrollTimeline { public: - enum ScrollDirection { Horizontal, Vertical }; + enum ScrollDirection { + ScrollUp, + ScrollDown, + ScrollLeft, + ScrollRight, + }; ScrollTimeline(base::Optional<ElementId> scroller_id, - ScrollDirection orientation, + ScrollDirection direction, + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset, double time_range); virtual ~ScrollTimeline(); @@ -43,6 +45,9 @@ class CC_ANIMATION_EXPORT ScrollTimeline { bool is_active_tree) const; void SetScrollerId(base::Optional<ElementId> scroller_id); + void UpdateStartAndEndScrollOffsets( + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset); void PushPropertiesTo(ScrollTimeline* impl_timeline); @@ -55,9 +60,12 @@ class CC_ANIMATION_EXPORT ScrollTimeline { base::Optional<ElementId> active_id_; base::Optional<ElementId> pending_id_; - // The orientation of the ScrollTimeline indicates which axis of the scroller - // it should base its current time on - either the horizontal or vertical. - ScrollDirection orientation_; + // The direction of the ScrollTimeline indicates which axis of the scroller + // it should base its current time on, and where the origin point is. + ScrollDirection direction_; + + base::Optional<double> start_scroll_offset_; + base::Optional<double> end_scroll_offset_; // A ScrollTimeline maps from the scroll offset in the scroller to a time // value based on a 'time range'. See the implementation of CurrentTime or the diff --git a/chromium/cc/animation/scroll_timeline_unittest.cc b/chromium/cc/animation/scroll_timeline_unittest.cc index 686ee560bf9..0611014d9df 100644 --- a/chromium/cc/animation/scroll_timeline_unittest.cc +++ b/chromium/cc/animation/scroll_timeline_unittest.cc @@ -11,6 +11,8 @@ namespace cc { +namespace { + void SetScrollOffset(PropertyTrees* property_trees, ElementId scroller_id, gfx::ScrollOffset offset) { @@ -48,6 +50,19 @@ void CreateScrollingElement(PropertyTrees* property_trees, property_trees->element_id_to_scroll_node_index[scroller_id] = scroll_node_id; } +// Helper method to calculate the current time, implementing only step 5 of +// https://wicg.github.io/scroll-animations/#current-time-algorithm +double CalculateCurrentTime(double current_scroll_offset, + double start_scroll_offset, + double end_scroll_offset, + double effective_time_range) { + return ((current_scroll_offset - start_scroll_offset) / + (end_scroll_offset - start_scroll_offset)) * + effective_time_range; +} + +} // namespace + class ScrollTimelineTest : public ::testing::Test { public: ScrollTimelineTest() @@ -83,10 +98,10 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) { // just compute one edge and use it for vertical/horizontal. double time_range = content_size().height() - container_size().height(); - ScrollTimeline vertical_timeline(scroller_id(), ScrollTimeline::Vertical, - time_range); - ScrollTimeline horizontal_timeline(scroller_id(), ScrollTimeline::Horizontal, - time_range); + ScrollTimeline vertical_timeline(scroller_id(), ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, time_range); + ScrollTimeline horizontal_timeline(scroller_id(), ScrollTimeline::ScrollRight, + base::nullopt, base::nullopt, time_range); // Unscrolled, both timelines should read a current time of 0. SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset()); @@ -105,7 +120,8 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) { TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) { // Here we set a time range to 100, which gives the current time the form of // 'percentage scrolled'. - ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, 100); + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100); double halfwayY = (content_size().height() - container_size().height()) / 2.; SetScrollOffset(&property_trees(), scroller_id(), @@ -137,7 +153,8 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) { double halfwayY = (content_size().height() - container_size().height()) / 2.; SetScrollOffset(&pending_tree, scroller_id, gfx::ScrollOffset(0, halfwayY)); - ScrollTimeline main_timeline(scroller_id, ScrollTimeline::Vertical, 100); + ScrollTimeline main_timeline(scroller_id, ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100); // Now create an impl version of the ScrollTimeline. Initilly this should only // have a pending scroller id, as the active tree may not yet have the @@ -163,7 +180,8 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) { TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) { double time_range = content_size().height() - container_size().height(); - ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, time_range); + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, time_range); SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 50)); @@ -176,4 +194,85 @@ TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) { EXPECT_FLOAT_EQ(49.5, timeline.CurrentTime(scroll_tree(), false)); } +TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) { + double time_range = content_size().height() - container_size().height(); + const double start_scroll_offset = 20; + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, + start_scroll_offset, base::nullopt, time_range); + + // Unscrolled, the timeline should read a current time of unresolved, since + // the current offset (0) will be less than the startScrollOffset. + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset()); + EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); + + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 19)); + EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 20)); + EXPECT_FLOAT_EQ(0, timeline.CurrentTime(scroll_tree(), false)); + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 50)); + EXPECT_FLOAT_EQ( + CalculateCurrentTime(50, start_scroll_offset, time_range, time_range), + timeline.CurrentTime(scroll_tree(), false)); + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 200)); + EXPECT_FLOAT_EQ( + CalculateCurrentTime(200, start_scroll_offset, time_range, time_range), + timeline.CurrentTime(scroll_tree(), false)); +} + +TEST_F(ScrollTimelineTest, CurrentTimeHandlesEndScrollOffset) { + double time_range = content_size().height() - container_size().height(); + const double end_scroll_offset = time_range - 20; + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, + base::nullopt, end_scroll_offset, time_range); + + SetScrollOffset(&property_trees(), scroller_id(), + gfx::ScrollOffset(0, time_range)); + EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); + SetScrollOffset(&property_trees(), scroller_id(), + gfx::ScrollOffset(0, time_range - 20)); + EXPECT_FLOAT_EQ( + CalculateCurrentTime(time_range - 20, 0, end_scroll_offset, time_range), + timeline.CurrentTime(scroll_tree(), false)); + SetScrollOffset(&property_trees(), scroller_id(), + gfx::ScrollOffset(0, time_range - 50)); + EXPECT_FLOAT_EQ( + CalculateCurrentTime(time_range - 50, 0, end_scroll_offset, time_range), + timeline.CurrentTime(scroll_tree(), false)); + SetScrollOffset(&property_trees(), scroller_id(), + gfx::ScrollOffset(0, time_range - 200)); + EXPECT_FLOAT_EQ( + CalculateCurrentTime(time_range - 200, 0, end_scroll_offset, time_range), + timeline.CurrentTime(scroll_tree(), false)); +} + +TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) { + double time_range = content_size().height() - container_size().height(); + double start_scroll_offset = 20; + double end_scroll_offset = time_range - 50; + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, + start_scroll_offset, end_scroll_offset, time_range); + SetScrollOffset(&property_trees(), scroller_id(), + gfx::ScrollOffset(0, time_range - 150)); + EXPECT_FLOAT_EQ(CalculateCurrentTime(time_range - 150, start_scroll_offset, + end_scroll_offset, time_range), + timeline.CurrentTime(scroll_tree(), false)); +} + +TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) { + double time_range = content_size().height() - container_size().height(); + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, 20, 20, + time_range); + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150)); + EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); +} + +TEST_F(ScrollTimelineTest, + CurrentTimeHandlesStartOffsetLargerThanEndScrollOffset) { + double time_range = content_size().height() - container_size().height(); + ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, 50, 10, + time_range); + SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150)); + EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); +} + } // namespace cc diff --git a/chromium/cc/animation/worklet_animation.cc b/chromium/cc/animation/worklet_animation.cc index 34a9746df3c..b6f359038ef 100644 --- a/chromium/cc/animation/worklet_animation.cc +++ b/chromium/cc/animation/worklet_animation.cc @@ -108,12 +108,19 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, double current_time = CurrentTime(monotonic_time, scroll_tree, is_active_tree); + // TODO(yigu): If current_time becomes newly unresolved and last_current_time_ + // is resolved, we apply the last current time to the animation if the scroll + // timeline becomes newly inactive. See https://crbug.com/906050. last_current_time_ = current_time; switch (state_) { case State::PENDING: - input_state->Add( - {worklet_animation_id(), name(), current_time, CloneOptions()}); + // TODO(yigu): cc side WorkletAnimation is only capable of handling single + // keyframe effect at the moment. We should pass in the number of effects + // once Worklet Group Effect is fully implemented in cc. + // https://crbug.com/767043. + input_state->Add({worklet_animation_id(), name(), current_time, + CloneOptions(), 1 /* num_effects */}); state_ = State::RUNNING; break; case State::RUNNING: @@ -127,7 +134,10 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, void WorkletAnimation::SetOutputState( const MutatorOutputState::AnimationState& state) { - local_time_ = state.local_time; + // TODO(yigu): cc side WorkletAnimation is only capable of handling single + // keyframe effect at the moment. https://crbug.com/767043. + DCHECK_EQ(state.local_times.size(), 1u); + local_time_ = state.local_times[0]; } // TODO(crbug.com/780151): Multiply the result by the play back rate. @@ -159,11 +169,15 @@ bool WorkletAnimation::NeedsUpdate(base::TimeTicks monotonic_time, return needs_update; } -void WorkletAnimation::SetScrollSourceId( - base::Optional<ElementId> scroller_id) { +void WorkletAnimation::UpdateScrollTimeline( + base::Optional<ElementId> scroller_id, + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset) { // Calling this method implies that we are a ScrollTimeline based animation, // so the below call is done unchecked. scroll_timeline_->SetScrollerId(scroller_id); + scroll_timeline_->UpdateStartAndEndScrollOffsets(start_scroll_offset, + end_scroll_offset); SetNeedsPushProperties(); } diff --git a/chromium/cc/animation/worklet_animation.h b/chromium/cc/animation/worklet_animation.h index 1ab919d555e..fc8e67e0f01 100644 --- a/chromium/cc/animation/worklet_animation.h +++ b/chromium/cc/animation/worklet_animation.h @@ -60,10 +60,11 @@ class CC_ANIMATION_EXPORT WorkletAnimation final void PushPropertiesTo(Animation* animation_impl) override; - // Should be called when the scroll source of the ScrollTimeline attached to - // this animation has a change in ElementId. Such a change happens when the - // scroll source changes compositing state. - void SetScrollSourceId(base::Optional<ElementId> scroller_id); + // Should be called when the ScrollTimeline attached to this animation has a + // change, such as when the scroll source changes ElementId. + void UpdateScrollTimeline(base::Optional<ElementId> scroller_id, + base::Optional<double> start_scroll_offset, + base::Optional<double> end_scroll_offset); // Should be called when the pending tree is promoted to active, as this may // require updating the ElementId for the ScrollTimeline scroll source. diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc index 673c2cc1985..c8d009f4adf 100644 --- a/chromium/cc/animation/worklet_animation_unittest.cc +++ b/chromium/cc/animation/worklet_animation_unittest.cc @@ -49,7 +49,11 @@ class WorkletAnimationTest : public AnimationTimelinesTest { class MockScrollTimeline : public ScrollTimeline { public: MockScrollTimeline() - : ScrollTimeline(ElementId(), ScrollTimeline::Vertical, 0) {} + : ScrollTimeline(ElementId(), + ScrollTimeline::ScrollDown, + base::nullopt, + base::nullopt, + 0) {} MOCK_CONST_METHOD2(CurrentTime, double(const ScrollTree&, bool)); }; @@ -64,8 +68,10 @@ TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) { false /* not impl instance*/, std::move(effect))); EXPECT_CALL(*mock_effect, Tick(_)).Times(0); - worklet_animation->SetOutputState( - {worklet_animation_id_, base::TimeDelta::FromSecondsD(1)}); + + MutatorOutputState::AnimationState state(worklet_animation_id_); + state.local_times.push_back(base::TimeDelta::FromSecondsD(1)); + worklet_animation->SetOutputState(state); worklet_animation->Tick(base::TimeTicks()); } @@ -87,7 +93,9 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWhenTicking) { keyframe_model->set_needs_synchronized_start_time(false); base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2); - worklet_animation_->SetOutputState({worklet_animation_id_, local_time}); + MutatorOutputState::AnimationState state(worklet_animation_id_); + state.local_times.push_back(local_time); + worklet_animation_->SetOutputState(state); worklet_animation_->Tick(base::TimeTicks()); diff --git a/chromium/cc/base/completion_event.h b/chromium/cc/base/completion_event.h index 0c620db4e72..5c9debd64f4 100644 --- a/chromium/cc/base/completion_event.h +++ b/chromium/cc/base/completion_event.h @@ -39,7 +39,8 @@ class CompletionEvent { DCHECK(!waited_); waited_ = true; #endif - base::ThreadRestrictions::ScopedAllowWait allow_wait; + // http://crbug.com/902653 + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; event_.Wait(); } @@ -48,7 +49,8 @@ class CompletionEvent { DCHECK(!waited_); waited_ = true; #endif - base::ThreadRestrictions::ScopedAllowWait allow_wait; + // http://crbug.com/902653 + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; if (event_.TimedWait(max_time)) return true; #if DCHECK_IS_ON() diff --git a/chromium/cc/base/devtools_instrumentation.cc b/chromium/cc/base/devtools_instrumentation.cc index d6f77f027e3..fab22da704c 100644 --- a/chromium/cc/base/devtools_instrumentation.cc +++ b/chromium/cc/base/devtools_instrumentation.cc @@ -8,9 +8,8 @@ namespace cc { namespace devtools_instrumentation { namespace internal { -const char kCategory[] = TRACE_DISABLED_BY_DEFAULT("devtools.timeline"); -const char kCategoryFrame[] = - TRACE_DISABLED_BY_DEFAULT("devtools.timeline.frame"); +constexpr const char CategoryName::CategoryName::kTimeline[]; +constexpr const char CategoryName::CategoryName::kTimelineFrame[]; const char kData[] = "data"; const char kFrameId[] = "frameId"; const char kLayerId[] = "layerId"; @@ -36,13 +35,14 @@ ScopedImageDecodeTask::ScopedImageDecodeTask(const void* image_ptr, : decode_type_(decode_type), task_type_(task_type), start_time_(base::TimeTicks::Now()) { - TRACE_EVENT_BEGIN1(internal::kCategory, internal::kImageDecodeTask, - internal::kPixelRefId, + TRACE_EVENT_BEGIN1(internal::CategoryName::kTimeline, + internal::kImageDecodeTask, internal::kPixelRefId, reinterpret_cast<uint64_t>(image_ptr)); } ScopedImageDecodeTask::~ScopedImageDecodeTask() { - TRACE_EVENT_END0(internal::kCategory, internal::kImageDecodeTask); + TRACE_EVENT_END0(internal::CategoryName::kTimeline, + internal::kImageDecodeTask); base::TimeDelta duration = base::TimeTicks::Now() - start_time_; switch (task_type_) { case kInRaster: diff --git a/chromium/cc/base/devtools_instrumentation.h b/chromium/cc/base/devtools_instrumentation.h index 0562877ed4a..0697422a428 100644 --- a/chromium/cc/base/devtools_instrumentation.h +++ b/chromium/cc/base/devtools_instrumentation.h @@ -12,15 +12,21 @@ #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/base_export.h" namespace cc { namespace devtools_instrumentation { namespace internal { -CC_BASE_EXPORT extern const char kCategory[]; -CC_BASE_EXPORT extern const char kCategoryFrame[]; +struct CC_BASE_EXPORT CategoryName { + // Put these strings into a struct to allow external linkage. + static constexpr const char kTimeline[] = + TRACE_DISABLED_BY_DEFAULT("devtools.timeline"); + static constexpr const char kTimelineFrame[] = + TRACE_DISABLED_BY_DEFAULT("devtools.timeline.frame"); +}; + CC_BASE_EXPORT extern const char kData[]; CC_BASE_EXPORT extern const char kFrameId[]; CC_BASE_EXPORT extern const char kLayerId[]; @@ -44,10 +50,12 @@ class CC_BASE_EXPORT ScopedLayerTask { public: ScopedLayerTask(const char* event_name, int layer_id) : event_name_(event_name) { - TRACE_EVENT_BEGIN1(internal::kCategory, event_name_, internal::kLayerId, - layer_id); + TRACE_EVENT_BEGIN1(internal::CategoryName::kTimeline, event_name_, + internal::kLayerId, layer_id); + } + ~ScopedLayerTask() { + TRACE_EVENT_END0(internal::CategoryName::kTimeline, event_name_); } - ~ScopedLayerTask() { TRACE_EVENT_END0(internal::kCategory, event_name_); } private: const char* event_name_; @@ -78,10 +86,13 @@ class CC_BASE_EXPORT ScopedLayerTreeTask { int layer_id, int layer_tree_host_id) : event_name_(event_name) { - TRACE_EVENT_BEGIN2(internal::kCategory, event_name_, internal::kLayerId, - layer_id, internal::kLayerTreeId, layer_tree_host_id); + TRACE_EVENT_BEGIN2(internal::CategoryName::kTimeline, event_name_, + internal::kLayerId, layer_id, internal::kLayerTreeId, + layer_tree_host_id); + } + ~ScopedLayerTreeTask() { + TRACE_EVENT_END0(internal::CategoryName::kTimeline, event_name_); } - ~ScopedLayerTreeTask() { TRACE_EVENT_END0(internal::kCategory, event_name_); } private: const char* event_name_; @@ -92,11 +103,13 @@ class CC_BASE_EXPORT ScopedLayerTreeTask { struct CC_BASE_EXPORT ScopedCommitTrace { public: explicit ScopedCommitTrace(int layer_tree_host_id) { - TRACE_EVENT_BEGIN1(internal::kCategory, internal::kCompositeLayers, - internal::kLayerTreeId, layer_tree_host_id); + TRACE_EVENT_BEGIN1(internal::CategoryName::kTimeline, + internal::kCompositeLayers, internal::kLayerTreeId, + layer_tree_host_id); } ~ScopedCommitTrace() { - TRACE_EVENT_END0(internal::kCategory, internal::kCompositeLayers); + TRACE_EVENT_END0(internal::CategoryName::kTimeline, + internal::kCompositeLayers); } private: @@ -104,11 +117,13 @@ struct CC_BASE_EXPORT ScopedCommitTrace { }; struct CC_BASE_EXPORT ScopedLayerObjectTracker - : public base::trace_event::TraceScopedTrackableObject<int> { + : public base::trace_event:: + TraceScopedTrackableObject<int, internal::CategoryName::kTimeline> { explicit ScopedLayerObjectTracker(int layer_id) - : base::trace_event::TraceScopedTrackableObject<int>(internal::kCategory, - internal::kLayerId, - layer_id) {} + : base::trace_event:: + TraceScopedTrackableObject<int, internal::CategoryName::kTimeline>( + internal::kLayerId, + layer_id) {} private: DISALLOW_COPY_AND_ASSIGN(ScopedLayerObjectTracker); @@ -116,26 +131,27 @@ struct CC_BASE_EXPORT ScopedLayerObjectTracker inline void CC_BASE_EXPORT DidActivateLayerTree(int layer_tree_host_id, int frame_id) { - TRACE_EVENT_INSTANT2(internal::kCategoryFrame, internal::kActivateLayerTree, - TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, - layer_tree_host_id, internal::kFrameId, frame_id); + TRACE_EVENT_INSTANT2(internal::CategoryName::kTimelineFrame, + internal::kActivateLayerTree, TRACE_EVENT_SCOPE_THREAD, + internal::kLayerTreeId, layer_tree_host_id, + internal::kFrameId, frame_id); } inline void CC_BASE_EXPORT DidBeginFrame(int layer_tree_host_id) { - TRACE_EVENT_INSTANT1(internal::kCategoryFrame, internal::kBeginFrame, - TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, - layer_tree_host_id); + TRACE_EVENT_INSTANT1(internal::CategoryName::kTimelineFrame, + internal::kBeginFrame, TRACE_EVENT_SCOPE_THREAD, + internal::kLayerTreeId, layer_tree_host_id); } inline void CC_BASE_EXPORT DidDrawFrame(int layer_tree_host_id) { - TRACE_EVENT_INSTANT1(internal::kCategoryFrame, internal::kDrawFrame, - TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, - layer_tree_host_id); + TRACE_EVENT_INSTANT1(internal::CategoryName::kTimelineFrame, + internal::kDrawFrame, TRACE_EVENT_SCOPE_THREAD, + internal::kLayerTreeId, layer_tree_host_id); } inline void CC_BASE_EXPORT DidRequestMainThreadFrame(int layer_tree_host_id) { TRACE_EVENT_INSTANT1( - internal::kCategoryFrame, internal::kRequestMainThreadFrame, + internal::CategoryName::kTimelineFrame, internal::kRequestMainThreadFrame, TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, layer_tree_host_id); } @@ -150,7 +166,7 @@ BeginMainThreadFrameData(int frame_id) { inline void CC_BASE_EXPORT WillBeginMainThreadFrame(int layer_tree_host_id, int frame_id) { TRACE_EVENT_INSTANT2( - internal::kCategoryFrame, internal::kBeginMainThreadFrame, + internal::CategoryName::kTimelineFrame, internal::kBeginMainThreadFrame, TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, layer_tree_host_id, internal::kData, BeginMainThreadFrameData(frame_id)); } @@ -166,7 +182,7 @@ NeedsBeginFrameData(bool needs_begin_frame) { inline void CC_BASE_EXPORT NeedsBeginFrameChanged(int layer_tree_host_id, bool new_value) { TRACE_EVENT_INSTANT2( - internal::kCategoryFrame, internal::kNeedsBeginFrameChanged, + internal::CategoryName::kTimelineFrame, internal::kNeedsBeginFrameChanged, TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, layer_tree_host_id, internal::kData, NeedsBeginFrameData(new_value)); } diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc index 7ac7fb42f5e..d212a733474 100644 --- a/chromium/cc/base/math_util.cc +++ b/chromium/cc/base/math_util.cc @@ -11,7 +11,7 @@ #include <xmmintrin.h> #endif -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "ui/gfx/geometry/angle_conversions.h" #include "ui/gfx/geometry/quad_f.h" diff --git a/chromium/cc/base/region.cc b/chromium/cc/base/region.cc index 5653634e8fa..3187693ce30 100644 --- a/chromium/cc/base/region.cc +++ b/chromium/cc/base/region.cc @@ -6,7 +6,7 @@ #include <stddef.h> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/base/simple_enclosed_region.h" #include "ui/gfx/geometry/vector2d.h" diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h index d6a1e8d8da8..840eaabe079 100644 --- a/chromium/cc/base/rtree.h +++ b/chromium/cc/base/rtree.h @@ -61,12 +61,12 @@ class RTree { // Given a query rect, returns elements that intersect the rect. Elements are // returned in the order they appeared in the initial container. - std::vector<T> Search(const gfx::Rect& query) const; + void Search(const gfx::Rect& query, std::vector<T>* results) const; // Given a query rect, returns non-owning pointers to elements that intersect // the rect. Elements are returned in the order they appeared in the initial // container. - std::vector<const T*> SearchRefs(const gfx::Rect& query) const; + void SearchRefs(const gfx::Rect& query, std::vector<const T*>* results) const; // Returns the total bounds of all items in this rtree. gfx::Rect GetBounds() const; @@ -288,19 +288,18 @@ auto RTree<T>::BuildRecursive(std::vector<Branch<T>>* branches, int level) } template <typename T> -std::vector<T> RTree<T>::Search(const gfx::Rect& query) const { - std::vector<T> results; +void RTree<T>::Search(const gfx::Rect& query, std::vector<T>* results) const { + results->clear(); if (num_data_elements_ > 0 && query.Intersects(root_.bounds)) - SearchRecursive(root_.subtree, query, &results); - return results; + SearchRecursive(root_.subtree, query, results); } template <typename T> -std::vector<const T*> RTree<T>::SearchRefs(const gfx::Rect& query) const { - std::vector<const T*> results; +void RTree<T>::SearchRefs(const gfx::Rect& query, + std::vector<const T*>* results) const { + results->clear(); if (num_data_elements_ > 0 && query.Intersects(root_.bounds)) - SearchRefsRecursive(root_.subtree, query, &results); - return results; + SearchRefsRecursive(root_.subtree, query, results); } template <typename T> diff --git a/chromium/cc/base/rtree_perftest.cc b/chromium/cc/base/rtree_perftest.cc index e7c70d5b1f2..70d44bcd843 100644 --- a/chromium/cc/base/rtree_perftest.cc +++ b/chromium/cc/base/rtree_perftest.cc @@ -58,7 +58,9 @@ class RTreePerfTest : public testing::Test { timer_.Reset(); do { - Accumulate(rtree.Search(queries[query_index])); + std::vector<size_t> results; + rtree.Search(queries[query_index], &results); + Accumulate(results); query_index = (query_index + 1) % queries.size(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); diff --git a/chromium/cc/base/rtree_unittest.cc b/chromium/cc/base/rtree_unittest.cc index d5242a1a4aa..e5b937942d9 100644 --- a/chromium/cc/base/rtree_unittest.cc +++ b/chromium/cc/base/rtree_unittest.cc @@ -35,20 +35,21 @@ TEST(RTreeTest, NoOverlap) { RTree<size_t> rtree; rtree.Build(rects); - std::vector<size_t> results = rtree.Search(gfx::Rect(0, 0, 50, 50)); + std::vector<size_t> results; + rtree.Search(gfx::Rect(0, 0, 50, 50), &results); ASSERT_EQ(2500u, results.size()); // Note that the results have to be sorted. for (size_t i = 0; i < 2500; ++i) { ASSERT_EQ(results[i], i); } - results = rtree.Search(gfx::Rect(0, 0, 50, 49)); + rtree.Search(gfx::Rect(0, 0, 50, 49), &results); ASSERT_EQ(2450u, results.size()); for (size_t i = 0; i < 2450; ++i) { ASSERT_EQ(results[i], i); } - results = rtree.Search(gfx::Rect(5, 6, 1, 1)); + rtree.Search(gfx::Rect(5, 6, 1, 1), &results); ASSERT_EQ(1u, results.size()); EXPECT_EQ(6u * 50 + 5u, results[0]); } @@ -64,14 +65,15 @@ TEST(RTreeTest, Overlap) { RTree<size_t> rtree; rtree.Build(rects); - std::vector<size_t> results = rtree.Search(gfx::Rect(0, 0, 1, 1)); + std::vector<size_t> results; + rtree.Search(gfx::Rect(0, 0, 1, 1), &results); ASSERT_EQ(2500u, results.size()); // Both the checks for the elements assume elements are sorted. for (size_t i = 0; i < 2500; ++i) { ASSERT_EQ(results[i], i); } - results = rtree.Search(gfx::Rect(0, 49, 1, 1)); + rtree.Search(gfx::Rect(0, 49, 1, 1), &results); ASSERT_EQ(50u, results.size()); for (size_t i = 0; i < 50; ++i) { EXPECT_EQ(results[i], 2450u + i); @@ -100,9 +102,13 @@ TEST(RTreeTest, SortedResults) { for (int y = 0; y < 50; ++y) { for (int x = 0; x < 50; ++x) { - VerifySorted(rtree.Search(gfx::Rect(x, y, 1, 1))); - VerifySorted(rtree.Search(gfx::Rect(x, y, 50, 1))); - VerifySorted(rtree.Search(gfx::Rect(x, y, 1, 50))); + std::vector<size_t> results; + rtree.Search(gfx::Rect(x, y, 1, 1), &results); + VerifySorted(results); + rtree.Search(gfx::Rect(x, y, 50, 1), &results); + VerifySorted(results); + rtree.Search(gfx::Rect(x, y, 1, 50), &results); + VerifySorted(results); } } } @@ -172,11 +178,12 @@ TEST(RTreeTest, Payload) { [](const Container& items, size_t index) { return items[index].first; }, [](const Container& items, size_t index) { return items[index].second; }); - auto results = rtree.Search(gfx::Rect(0, 0, 1, 1)); + std::vector<float> results; + rtree.Search(gfx::Rect(0, 0, 1, 1), &results); ASSERT_EQ(1u, results.size()); EXPECT_FLOAT_EQ(10.f, results[0]); - results = rtree.Search(gfx::Rect(5, 5, 10, 10)); + rtree.Search(gfx::Rect(5, 5, 10, 10), &results); ASSERT_EQ(4u, results.size()); // Items returned should be in the order they were inserted. EXPECT_FLOAT_EQ(40.f, results[0]); diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc index 8b70bc435c2..d363fe84b1d 100644 --- a/chromium/cc/base/switches.cc +++ b/chromium/cc/base/switches.cc @@ -84,8 +84,7 @@ const char kUIShowSurfaceDamageRects[] = "ui-show-surface-damage-rects"; const char kShowScreenSpaceRects[] = "show-screenspace-rects"; const char kUIShowScreenSpaceRects[] = "ui-show-screenspace-rects"; -// Switches cc machinery to use layer lists instead of layer trees -const char kEnableLayerLists[] = "enable-layer-lists"; +// Switches the ui compositor to use layer lists instead of layer trees. const char kUIEnableLayerLists[] = "ui-enable-layer-lists"; // Prevents the layer tree unit tests from timing out. diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h index 7234ee4024c..fe8de281021 100644 --- a/chromium/cc/base/switches.h +++ b/chromium/cc/base/switches.h @@ -44,7 +44,6 @@ CC_BASE_EXPORT extern const char kShowSurfaceDamageRects[]; CC_BASE_EXPORT extern const char kUIShowSurfaceDamageRects[]; CC_BASE_EXPORT extern const char kShowScreenSpaceRects[]; CC_BASE_EXPORT extern const char kUIShowScreenSpaceRects[]; -CC_BASE_EXPORT extern const char kEnableLayerLists[]; CC_BASE_EXPORT extern const char kUIEnableLayerLists[]; CC_BASE_EXPORT extern const char kCompositedRenderPassBorders[]; CC_BASE_EXPORT extern const char kCompositedSurfaceBorders[]; diff --git a/chromium/cc/benchmarks/benchmark_instrumentation.h b/chromium/cc/benchmarks/benchmark_instrumentation.h index 9b5e5efef97..d946c6e6b25 100644 --- a/chromium/cc/benchmarks/benchmark_instrumentation.h +++ b/chromium/cc/benchmarks/benchmark_instrumentation.h @@ -18,7 +18,11 @@ namespace benchmark_instrumentation { // The benchmarks search for events and their arguments by name. namespace internal { -const char kCategory[] = "cc,benchmark"; +constexpr const char* Category() { + // Declared as a constexpr function to have an external linkage and to be + // known at compile-time. + return "cc,benchmark"; +} const char kBeginFrameId[] = "begin_frame_id"; } // namespace internal @@ -31,11 +35,11 @@ class ScopedBeginFrameTask { public: ScopedBeginFrameTask(const char* event_name, unsigned int begin_frame_id) : event_name_(event_name) { - TRACE_EVENT_BEGIN1(internal::kCategory, event_name_, + TRACE_EVENT_BEGIN1(internal::Category(), event_name_, internal::kBeginFrameId, begin_frame_id); } ~ScopedBeginFrameTask() { - TRACE_EVENT_END0(internal::kCategory, event_name_); + TRACE_EVENT_END0(internal::Category(), event_name_); } private: diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc index e4d5e25a8aa..d3652f0dba9 100644 --- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc +++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc @@ -65,8 +65,8 @@ void RunBenchmark(RasterSource* raster_source, image_settings->images_to_skip = {}; image_settings->image_to_current_frame_index = {}; - PlaybackImageProvider image_provider( - image_decode_cache, gfx::ColorSpace(), std::move(image_settings)); + PlaybackImageProvider image_provider(image_decode_cache, + std::move(image_settings)); RasterSource::PlaybackSettings settings; settings.image_provider = &image_provider; diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc index 56b88794b87..6b51ff0b6f5 100644 --- a/chromium/cc/debug/layer_tree_debug_state.cc +++ b/chromium/cc/debug/layer_tree_debug_state.cc @@ -24,6 +24,7 @@ LayerTreeDebugState::LayerTreeDebugState() slow_down_raster_scale_factor(0), rasterize_only_visible_content(false), show_picture_borders(false), + show_hit_test_borders(false), record_rendering_stats_(false) {} LayerTreeDebugState::LayerTreeDebugState(const LayerTreeDebugState& other) = @@ -73,6 +74,7 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, a.slow_down_raster_scale_factor == b.slow_down_raster_scale_factor && a.rasterize_only_visible_content == b.rasterize_only_visible_content && a.show_picture_borders == b.show_picture_borders && + a.show_hit_test_borders == b.show_hit_test_borders && a.record_rendering_stats_ == b.record_rendering_stats_); } @@ -98,6 +100,8 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a, r.rasterize_only_visible_content |= b.rasterize_only_visible_content; r.show_picture_borders |= b.show_picture_borders; + r.show_hit_test_borders |= b.show_hit_test_borders; + r.record_rendering_stats_ |= b.record_rendering_stats_; return r; diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h index 2ea5f9c3aa9..c7438b6fe48 100644 --- a/chromium/cc/debug/layer_tree_debug_state.h +++ b/chromium/cc/debug/layer_tree_debug_state.h @@ -46,6 +46,8 @@ class CC_DEBUG_EXPORT LayerTreeDebugState { bool rasterize_only_visible_content; bool show_picture_borders; + bool show_hit_test_borders; + void SetRecordRenderingStats(bool enabled); bool RecordRenderingStats() const; diff --git a/chromium/cc/debug/rendering_stats.h b/chromium/cc/debug/rendering_stats.h index 156db0c15b9..4fe3f55336d 100644 --- a/chromium/cc/debug/rendering_stats.h +++ b/chromium/cc/debug/rendering_stats.h @@ -11,7 +11,7 @@ #include <vector> #include "base/time/time.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/debug/debug_export.h" diff --git a/chromium/cc/input/browser_controls_offset_manager.cc b/chromium/cc/input/browser_controls_offset_manager.cc index e55bf940440..afbe9770086 100644 --- a/chromium/cc/input/browser_controls_offset_manager.cc +++ b/chromium/cc/input/browser_controls_offset_manager.cc @@ -38,6 +38,7 @@ BrowserControlsOffsetManager::BrowserControlsOffsetManager( float controls_show_threshold, float controls_hide_threshold) : client_(client), + animation_initialized_(false), animation_start_value_(0.f), animation_stop_value_(0.f), animation_direction_(NO_ANIMATION), @@ -47,7 +48,8 @@ BrowserControlsOffsetManager::BrowserControlsOffsetManager( baseline_bottom_content_offset_(0.f), controls_show_threshold_(controls_hide_threshold), controls_hide_threshold_(controls_show_threshold), - pinch_gesture_active_(false) { + pinch_gesture_active_(false), + constraint_changed_since_commit_(false) { CHECK(client_); } @@ -92,6 +94,17 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState( DCHECK(!(constraints == BrowserControlsState::kHidden && current == BrowserControlsState::kShown)); + TRACE_EVENT2("cc", "BrowserControlsOffsetManager::UpdateBrowserControlsState", + "constraints", static_cast<int>(constraints), "current", + static_cast<int>(current)); + + // If the constraints have changed we need to inform Blink about it since + // that'll affect main thread scrolling as well as layout. + if (permitted_state_ != constraints) { + constraint_changed_since_commit_ = true; + client_->SetNeedsCommit(); + } + permitted_state_ = constraints; // Don't do anything if it doesn't matter which state the controls are in. @@ -105,6 +118,7 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState( current == BrowserControlsState::kHidden) final_shown_ratio = 0.f; if (final_shown_ratio == TopControlsShownRatio()) { + TRACE_EVENT_INSTANT0("cc", "Ratio Unchanged", TRACE_EVENT_SCOPE_THREAD); ResetAnimations(); return; } @@ -113,10 +127,18 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState( SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS); } else { ResetAnimations(); - // We depend on the main thread to push the new ratio. crbug.com/754346 . + client_->SetCurrentBrowserControlsShownRatio(final_shown_ratio); } } +BrowserControlsState BrowserControlsOffsetManager::PullConstraintForMainThread( + bool* out_changed_since_commit) { + DCHECK(out_changed_since_commit); + *out_changed_since_commit = constraint_changed_since_commit_; + constraint_changed_since_commit_ = false; + return permitted_state_; +} + void BrowserControlsOffsetManager::ScrollBegin() { if (pinch_gesture_active_) return; @@ -197,6 +219,16 @@ gfx::Vector2dF BrowserControlsOffsetManager::Animate( if (!has_animation() || !client_->HaveRootScrollNode()) return gfx::Vector2dF(); + if (!animation_initialized_) { + // Setup the animation start and time here so that they use the same clock + // as frame times. This is helpful for tests that mock time. + animation_start_time_ = monotonic_time; + animation_stop_time_ = + animation_start_time_ + + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); + animation_initialized_ = true; + } + float old_offset = ContentTopOffset(); float new_ratio = gfx::Tween::ClampedFloatValueBetween( monotonic_time, animation_start_time_, animation_start_value_, @@ -211,6 +243,7 @@ gfx::Vector2dF BrowserControlsOffsetManager::Animate( } void BrowserControlsOffsetManager::ResetAnimations() { + animation_initialized_ = false; animation_start_time_ = base::TimeTicks(); animation_start_value_ = 0.f; animation_stop_time_ = base::TimeTicks(); @@ -234,13 +267,9 @@ void BrowserControlsOffsetManager::SetupAnimation( return; } - animation_start_time_ = base::TimeTicks::Now(); animation_start_value_ = TopControlsShownRatio(); const float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1); - animation_stop_time_ = - animation_start_time_ + - base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); animation_stop_value_ = animation_start_value_ + max_ending_ratio; animation_direction_ = direction; diff --git a/chromium/cc/input/browser_controls_offset_manager.h b/chromium/cc/input/browser_controls_offset_manager.h index ae4d9e4268f..8d0435d2808 100644 --- a/chromium/cc/input/browser_controls_offset_manager.h +++ b/chromium/cc/input/browser_controls_offset_manager.h @@ -53,6 +53,9 @@ class CC_EXPORT BrowserControlsOffsetManager { BrowserControlsState current, bool animate); + BrowserControlsState PullConstraintForMainThread( + bool* out_changed_since_commit); + void ScrollBegin(); gfx::Vector2dF ScrollBy(const gfx::Vector2dF& pending_delta); void ScrollEnd(); @@ -81,6 +84,9 @@ class CC_EXPORT BrowserControlsOffsetManager { // The client manages the lifecycle of this. BrowserControlsOffsetManagerClient* client_; + // animation_initialized_ tracks if we've initialized the start and end + // times since that must happen at a BeginFrame. + bool animation_initialized_; base::TimeTicks animation_start_time_; float animation_start_value_; base::TimeTicks animation_stop_time_; @@ -106,6 +112,10 @@ class CC_EXPORT BrowserControlsOffsetManager { bool pinch_gesture_active_; + // Used to track whether the constraint has changed and we need up reflect + // the changes to Blink. + bool constraint_changed_since_commit_; + DISALLOW_COPY_AND_ASSIGN(BrowserControlsOffsetManager); }; diff --git a/chromium/cc/input/browser_controls_offset_manager_client.h b/chromium/cc/input/browser_controls_offset_manager_client.h index df1a742669d..5a2ce4cb5dc 100644 --- a/chromium/cc/input/browser_controls_offset_manager_client.h +++ b/chromium/cc/input/browser_controls_offset_manager_client.h @@ -15,6 +15,7 @@ class CC_EXPORT BrowserControlsOffsetManagerClient { virtual float CurrentBrowserControlsShownRatio() const = 0; virtual void DidChangeBrowserControlsPosition() = 0; virtual bool HaveRootScrollNode() const = 0; + virtual void SetNeedsCommit() = 0; protected: virtual ~BrowserControlsOffsetManagerClient() {} diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc index 3caad9cd2ec..3a8cfdc7df8 100644 --- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc +++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc @@ -71,6 +71,8 @@ class MockBrowserControlsOffsetManagerClient return top_controls_shown_ratio_; } + void SetNeedsCommit() override {} + LayerImpl* rootScrollLayer() { return root_scroll_layer_.get(); } BrowserControlsOffsetManager* manager() { @@ -167,7 +169,12 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownHideAnimation) { EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -199,7 +206,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->BottomControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -229,7 +241,12 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownShowAnimation) { EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -256,7 +273,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->BottomControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -283,7 +305,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -310,7 +337,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -341,7 +373,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -372,7 +409,12 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -435,7 +477,12 @@ TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { EXPECT_TRUE(manager->has_animation()); base::TimeTicks time = base::TimeTicks::Now(); - float previous; + + // First animate will establish the animaion. + float previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; @@ -456,6 +503,12 @@ TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { EXPECT_TRUE(manager->has_animation()); time = base::TimeTicks::Now(); + + // First animate will establish the animaion. + previous = manager->TopControlsShownRatio(); + manager->Animate(time); + EXPECT_EQ(manager->TopControlsShownRatio(), previous); + while (manager->has_animation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; diff --git a/chromium/cc/input/browser_controls_state.h b/chromium/cc/input/browser_controls_state.h index 38310496c5a..8b2f93f4171 100644 --- a/chromium/cc/input/browser_controls_state.h +++ b/chromium/cc/input/browser_controls_state.h @@ -8,6 +8,7 @@ namespace cc { enum class BrowserControlsState { kShown = 1, kHidden = 2, kBoth = 3 }; -} + +} // namespace cc #endif // CC_INPUT_BROWSER_CONTROLS_STATE_H_ diff --git a/chromium/cc/input/main_thread_scrolling_reason.cc b/chromium/cc/input/main_thread_scrolling_reason.cc index a85b60f97a7..728708ce776 100644 --- a/chromium/cc/input/main_thread_scrolling_reason.cc +++ b/chromium/cc/input/main_thread_scrolling_reason.cc @@ -5,7 +5,7 @@ #include "cc/input/main_thread_scrolling_reason.h" #include "base/stl_util.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" namespace cc { @@ -47,8 +47,6 @@ void MainThreadScrollingReason::AddToTracedValue( traced_value.AppendString("Has transform and LCD text"); if (reasons & kBackgroundNotOpaqueInRectAndLCDText) traced_value.AppendString("Background is not opaque in rect and LCD text"); - if (reasons & kHasBorderRadius) - traced_value.AppendString("Has border radius"); if (reasons & kHasClipRelatedProperty) traced_value.AppendString("Has clip related property"); if (reasons & kHasBoxShadowFromNonRootLayer) diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h index cf2deff0ce8..732c3fa904b 100644 --- a/chromium/cc/input/main_thread_scrolling_reason.h +++ b/chromium/cc/input/main_thread_scrolling_reason.h @@ -46,7 +46,6 @@ struct CC_EXPORT MainThreadScrollingReason { kHasOpacityAndLCDText = 1 << 16, kHasTransformAndLCDText = 1 << 17, kBackgroundNotOpaqueInRectAndLCDText = 1 << 18, - kHasBorderRadius = 1 << 19, kHasClipRelatedProperty = 1 << 20, kHasBoxShadowFromNonRootLayer = 1 << 21, kIsNotStackingContextAndLCDText = 1 << 22, @@ -72,9 +71,8 @@ struct CC_EXPORT MainThreadScrollingReason { static const uint32_t kNonCompositedReasons = kHasOpacityAndLCDText | kHasTransformAndLCDText | - kBackgroundNotOpaqueInRectAndLCDText | kHasBorderRadius | - kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer | - kIsNotStackingContextAndLCDText; + kBackgroundNotOpaqueInRectAndLCDText | kHasClipRelatedProperty | + kHasBoxShadowFromNonRootLayer | kIsNotStackingContextAndLCDText; // Returns true if the given MainThreadScrollingReason can be set by the main // thread. diff --git a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc index 9f8e6b641d8..7560dda71d9 100644 --- a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc +++ b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc @@ -16,13 +16,14 @@ TEST_F(MainThreadScrollingReasonTest, AsText) { "Has background-attachment:fixed," "Has non-layer viewport-constrained objects," "Threaded scrolling is disabled," - "Scrollbar scrolling,Page overlay," + "Scrollbar scrolling," + "Page overlay," "Handling scroll from main thread," "Custom scrollbar scrolling," "Has opacity and LCD text," "Has transform and LCD text," "Background is not opaque in rect and LCD text," - "Has border radius,Has clip related property," + "Has clip related property," "Has box shadow from non-root layer," "Is not stacking context and LCD text," "Non fast scrollable region," diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc index 9e873aea523..3fc17474fc7 100644 --- a/chromium/cc/input/scroll_snap_data.cc +++ b/chromium/cc/input/scroll_snap_data.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "cc/input/scroll_snap_data.h" +#include "cc/input/snap_selection_strategy.h" #include <algorithm> #include <cmath> @@ -11,8 +12,8 @@ namespace cc { namespace { bool IsMutualVisible(const SnapSearchResult& a, const SnapSearchResult& b) { - return a.visible_range().Contains(b.snap_offset()) && - b.visible_range().Contains(a.snap_offset()); + return a.visible_range().Contains(gfx::RangeF(b.snap_offset())) && + b.visible_range().Contains(gfx::RangeF(a.snap_offset())); } bool SnappableOnAxis(const SnapAreaData& area, SearchAxis search_axis) { @@ -21,34 +22,36 @@ bool SnappableOnAxis(const SnapAreaData& area, SearchAxis search_axis) { : area.scroll_snap_align.alignment_block != SnapAlignment::kNone; } -} // namespace - -bool SnapVisibleRange::Contains(float value) const { - if (start_ < end_) - return start_ <= value && value <= end_; - return end_ <= value && value <= start_; +void SetOrUpdateResult(const SnapSearchResult& candidate, + base::Optional<SnapSearchResult>* result) { + if (result->has_value()) + result->value().Union(candidate); + else + *result = candidate; } -SnapSearchResult::SnapSearchResult(float offset, const SnapVisibleRange& range) +} // namespace + +SnapSearchResult::SnapSearchResult(float offset, const gfx::RangeF& range) : snap_offset_(offset) { set_visible_range(range); } -void SnapSearchResult::set_visible_range(const SnapVisibleRange& range) { +void SnapSearchResult::set_visible_range(const gfx::RangeF& range) { DCHECK(range.start() <= range.end()); visible_range_ = range; } void SnapSearchResult::Clip(float max_snap, float max_visible) { snap_offset_ = std::max(std::min(snap_offset_, max_snap), 0.0f); - visible_range_ = SnapVisibleRange( - std::max(std::min(visible_range_.start(), max_visible), 0.0f), - std::max(std::min(visible_range_.end(), max_visible), 0.0f)); + visible_range_ = + gfx::RangeF(std::max(std::min(visible_range_.start(), max_visible), 0.0f), + std::max(std::min(visible_range_.end(), max_visible), 0.0f)); } void SnapSearchResult::Union(const SnapSearchResult& other) { DCHECK(snap_offset_ == other.snap_offset_); - visible_range_ = SnapVisibleRange( + visible_range_ = gfx::RangeF( std::min(visible_range_.start(), other.visible_range_.start()), std::max(visible_range_.end(), other.visible_range_.end())); } @@ -88,13 +91,14 @@ void SnapContainerData::AddSnapAreaData(SnapAreaData snap_area_data) { } bool SnapContainerData::FindSnapPosition( - const gfx::ScrollOffset& current_position, - bool should_snap_on_x, - bool should_snap_on_y, + const SnapSelectionStrategy& strategy, gfx::ScrollOffset* snap_position) const { + gfx::ScrollOffset base_position = strategy.base_position(); SnapAxis axis = scroll_snap_type_.axis; - should_snap_on_x &= (axis == SnapAxis::kX || axis == SnapAxis::kBoth); - should_snap_on_y &= (axis == SnapAxis::kY || axis == SnapAxis::kBoth); + bool should_snap_on_x = strategy.ShouldSnapOnX() && + (axis == SnapAxis::kX || axis == SnapAxis::kBoth); + bool should_snap_on_y = strategy.ShouldSnapOnY() && + (axis == SnapAxis::kY || axis == SnapAxis::kBoth); if (!should_snap_on_x && !should_snap_on_y) return false; @@ -102,18 +106,18 @@ bool SnapContainerData::FindSnapPosition( // A region that includes every reachable scroll position. gfx::RectF scrollable_region(0, 0, max_position_.x(), max_position_.y()); if (should_snap_on_x) { - // Start from current offset in the cross axis and assume it's always + // Start from current position in the cross axis and assume it's always // visible. SnapSearchResult initial_snap_position_y = { - current_position.y(), SnapVisibleRange(0, max_position_.x())}; - closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(), - initial_snap_position_y); + base_position.y(), gfx::RangeF(0, max_position_.x())}; + closest_x = + FindClosestValidArea(SearchAxis::kX, strategy, initial_snap_position_y); } if (should_snap_on_y) { SnapSearchResult initial_snap_position_x = { - current_position.x(), SnapVisibleRange(0, max_position_.y())}; - closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(), - initial_snap_position_x); + base_position.x(), gfx::RangeF(0, max_position_.y())}; + closest_y = + FindClosestValidArea(SearchAxis::kY, strategy, initial_snap_position_x); } if (!closest_x.has_value() && !closest_y.has_value()) @@ -126,17 +130,18 @@ bool SnapContainerData::FindSnapPosition( if (closest_x.has_value() && closest_y.has_value() && !IsMutualVisible(closest_x.value(), closest_y.value())) { bool candidate_on_x_axis_is_closer = - std::abs(closest_x.value().snap_offset() - current_position.x()) <= - std::abs(closest_y.value().snap_offset() - current_position.y()); - if (candidate_on_x_axis_is_closer) - closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(), - closest_x.value()); - else - closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(), - closest_y.value()); + std::abs(closest_x.value().snap_offset() - base_position.x()) <= + std::abs(closest_y.value().snap_offset() - base_position.y()); + if (candidate_on_x_axis_is_closer) { + closest_y = + FindClosestValidArea(SearchAxis::kY, strategy, closest_x.value()); + } else { + closest_x = + FindClosestValidArea(SearchAxis::kX, strategy, closest_y.value()); + } } - *snap_position = current_position; + *snap_position = strategy.current_position(); if (closest_x.has_value()) snap_position->set_x(closest_x.value().snap_offset()); if (closest_y.has_value()) @@ -146,13 +151,36 @@ bool SnapContainerData::FindSnapPosition( base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea( SearchAxis axis, - float current_offset, + const SnapSelectionStrategy& strategy, const SnapSearchResult& cros_axis_snap_result) const { - base::Optional<SnapSearchResult> result; - base::Optional<SnapSearchResult> inplace; - // The valid snap offsets immediately before and after the current offset. + // The search result from the snap area that's closest to the search origin. + base::Optional<SnapSearchResult> closest; + // The search result with the intended position if it makes a snap area cover + // the snapport. + base::Optional<SnapSearchResult> covering; + // The search result with the current position as a backup in case no other + // valid snap position exists. + base::Optional<SnapSearchResult> current; + + // The valid snap positions immediately before and after the current position. float prev = std::numeric_limits<float>::lowest(); float next = std::numeric_limits<float>::max(); + + // The current position before the scroll or snap happens. If no other snap + // position exists, this would become a backup option. + float current_position = axis == SearchAxis::kX + ? strategy.current_position().x() + : strategy.current_position().y(); + // The intended position of the scroll operation if there's no snap. This + // scroll position becomes the covering candidate if there is a snap area that + // fully covers the snapport if this position is scrolled to. + float intended_position = axis == SearchAxis::kX + ? strategy.intended_position().x() + : strategy.intended_position().y(); + // The position from which we search for the closest snap position. + float base_position = axis == SearchAxis::kX ? strategy.base_position().x() + : strategy.base_position().y(); + float smallest_distance = axis == SearchAxis::kX ? proximity_range_.x() : proximity_range_.y(); for (const SnapAreaData& area : snap_area_list_) { @@ -160,52 +188,54 @@ base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea( continue; SnapSearchResult candidate = GetSnapSearchResult(axis, area); - if (IsSnapportCoveredOnAxis(axis, current_offset, area.rect)) { - // Since snap area is currently covering the snapport, we consider the - // current offset as a valid snap position. - SnapSearchResult inplace_candidate = candidate; - inplace_candidate.set_snap_offset(current_offset); - if (IsMutualVisible(inplace_candidate, cros_axis_snap_result)) { - // If we've already found a valid overflowing area before, we enlarge - // the area's visible region. - if (inplace.has_value()) - inplace.value().Union(inplace_candidate); - else - inplace = inplace_candidate; - // Even if a snap area covers the snapport, we need to continue this - // search to find previous and next snap positions and also to have - // alternative snap candidates if this inplace candidate is ultimately - // rejected. And this covering snap area has its own alignment that may - // generates a snap position rejecting the current inplace candidate. - } + if (IsSnapportCoveredOnAxis(axis, intended_position, area.rect)) { + // Since snap area will cover the snapport, we consider the intended + // position as a valid snap position. + SnapSearchResult covering_candidate = candidate; + covering_candidate.set_snap_offset(intended_position); + if (IsMutualVisible(covering_candidate, cros_axis_snap_result)) + SetOrUpdateResult(covering_candidate, &covering); + // Even if a snap area covers the snapport, we need to continue this + // search to find previous and next snap positions and also to have + // alternative snap candidates if this covering candidate is ultimately + // rejected. And this covering snap area has its own alignment that may + // generates a snap position rejecting the current inplace candidate. } if (!IsMutualVisible(candidate, cros_axis_snap_result)) continue; - float distance = std::abs(candidate.snap_offset() - current_offset); + if (!strategy.IsValidSnapPosition(axis, candidate.snap_offset())) { + if (candidate.snap_offset() == current_position && + scroll_snap_type_.strictness == SnapStrictness::kMandatory) { + SetOrUpdateResult(candidate, ¤t); + } + continue; + } + float distance = std::abs(candidate.snap_offset() - base_position); if (distance < smallest_distance) { smallest_distance = distance; - result = candidate; + closest = candidate; } - if (candidate.snap_offset() < current_offset && + if (candidate.snap_offset() < intended_position && candidate.snap_offset() > prev) prev = candidate.snap_offset(); - if (candidate.snap_offset() > current_offset && + if (candidate.snap_offset() > intended_position && candidate.snap_offset() < next) next = candidate.snap_offset(); } // According to the spec [1], if the snap area is covering the snapport, the - // scroll offset is a valid snap position only if the distance between the + // scroll position is a valid snap position only if the distance between the // geometrically previous and subsequent snap positions in that axis is larger // than size of the snapport in that axis. // [1] https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow float size = axis == SearchAxis::kX ? rect_.width() : rect_.height(); - if (inplace.has_value() && - (prev == std::numeric_limits<float>::lowest() || - next == std::numeric_limits<float>::max() || next - prev > size)) { - return inplace; + if (prev != std::numeric_limits<float>::lowest() && + next != std::numeric_limits<float>::max() && next - prev <= size) { + covering = base::nullopt; } - return result; + const base::Optional<SnapSearchResult>& picked = + strategy.PickBestResult(closest, covering); + return picked.has_value() ? picked : current; } SnapSearchResult SnapContainerData::GetSnapSearchResult( @@ -213,8 +243,8 @@ SnapSearchResult SnapContainerData::GetSnapSearchResult( const SnapAreaData& area) const { SnapSearchResult result; if (axis == SearchAxis::kX) { - result.set_visible_range(SnapVisibleRange(area.rect.y() - rect_.bottom(), - area.rect.bottom() - rect_.y())); + result.set_visible_range(gfx::RangeF(area.rect.y() - rect_.bottom(), + area.rect.bottom() - rect_.y())); // https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-align switch (area.scroll_snap_align.alignment_inline) { case SnapAlignment::kStart: @@ -232,8 +262,8 @@ SnapSearchResult SnapContainerData::GetSnapSearchResult( } result.Clip(max_position_.x(), max_position_.y()); } else { - result.set_visible_range(SnapVisibleRange(area.rect.x() - rect_.right(), - area.rect.right() - rect_.x())); + result.set_visible_range(gfx::RangeF(area.rect.x() - rect_.right(), + area.rect.right() - rect_.x())); switch (area.scroll_snap_align.alignment_block) { case SnapAlignment::kStart: result.set_snap_offset(area.rect.y() - rect_.y()); diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h index c18f7374229..3057acf339e 100644 --- a/chromium/cc/input/scroll_snap_data.h +++ b/chromium/cc/input/scroll_snap_data.h @@ -11,9 +11,12 @@ #include "cc/cc_export.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/scroll_offset.h" +#include "ui/gfx/range/range_f.h" namespace cc { +class SnapSelectionStrategy; + // See https://www.w3.org/TR/css-scroll-snap-1/#snap-axis enum class SnapAxis : unsigned { kBoth, @@ -85,28 +88,13 @@ struct ScrollSnapAlign { SnapAlignment alignment_inline; }; -// We should really use gfx::RangeF. However, it includes windows.h which would -// bring in complexity to the compilation. https://crbug.com/855717 -class SnapVisibleRange { - public: - SnapVisibleRange() {} - SnapVisibleRange(float start, float end) : start_(start), end_(end) {} - bool Contains(float value) const; - float start() const { return start_; } - float end() const { return end_; } - - private: - float start_; - float end_; -}; - // This class includes snap offset and visible range needed to perform a snap // operation on one axis for a specific area. The data can be used to determine // whether this snap area provides a valid snap position for the current scroll. class SnapSearchResult { public: SnapSearchResult() {} - SnapSearchResult(float offset, const SnapVisibleRange& range); + SnapSearchResult(float offset, const gfx::RangeF& range); // Clips the |snap_offset| between 0 and |max_snap|. And clips the // |visible_range| between 0 and |max_visible|. void Clip(float max_snap, float max_visible); @@ -118,15 +106,15 @@ class SnapSearchResult { float snap_offset() const { return snap_offset_; } void set_snap_offset(float offset) { snap_offset_ = offset; } - SnapVisibleRange visible_range() const { return visible_range_; } - void set_visible_range(const SnapVisibleRange& range); + gfx::RangeF visible_range() const { return visible_range_; } + void set_visible_range(const gfx::RangeF& range); private: float snap_offset_; // This is the range on the cross axis, within which the SnapArea generating // this |snap_offset| is visible. We expect the range to be in order (as - // opposed to reversed), i.e., start < end. - SnapVisibleRange visible_range_; + // opposed to reversed), i.e., start() < end(). + gfx::RangeF visible_range_; }; // Snap area is a bounding box that could be snapped to when a scroll happens in @@ -196,9 +184,7 @@ class CC_EXPORT SnapContainerData { return !(*this == other); } - bool FindSnapPosition(const gfx::ScrollOffset& current_position, - bool should_snap_on_x, - bool should_snap_on_y, + bool FindSnapPosition(const SnapSelectionStrategy& strategy, gfx::ScrollOffset* snap_position) const; void AddSnapAreaData(SnapAreaData snap_area_data); @@ -222,8 +208,8 @@ class CC_EXPORT SnapContainerData { gfx::ScrollOffset proximity_range() const { return proximity_range_; } private: - // Finds the best SnapArea candidate that minimizes the distance between - // current and candidate positions, while satisfying two invariants: + // Finds the best SnapArea candidate that's optimal for the given selection + // strategy, while satisfying two invariants: // - |candidate.snap_offset| is within |cross_axis_snap_result|'s visible // range on |axis|. // - |cross_axis_snap_result.snap_offset| is within |candidate|'s visible @@ -234,7 +220,7 @@ class CC_EXPORT SnapContainerData { // |snap_offset| and its visible range on the cross axis. base::Optional<SnapSearchResult> FindClosestValidArea( SearchAxis axis, - float current_offset, + const SnapSelectionStrategy& strategy, const SnapSearchResult& cross_axis_snap_result) const; // Returns all the info needed to snap at this area on the given axis, diff --git a/chromium/cc/input/scroll_snap_data_unittest.cc b/chromium/cc/input/scroll_snap_data_unittest.cc index d2347148d0b..6f994d543a0 100644 --- a/chromium/cc/input/scroll_snap_data_unittest.cc +++ b/chromium/cc/input/scroll_snap_data_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "cc/input/scroll_snap_data.h" +#include "cc/input/snap_selection_strategy.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,10 +18,12 @@ TEST_F(ScrollSnapDataTest, StartAlignmentCalculation) { SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(100, 150, 100, 100), false); container.AddSnapAreaData(area); - gfx::ScrollOffset current_position(0, 0); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, + true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(90, snap_position.x()); EXPECT_EQ(140, snap_position.y()); } @@ -32,10 +35,12 @@ TEST_F(ScrollSnapDataTest, CenterAlignmentCalculation) { SnapAreaData area(ScrollSnapAlign(SnapAlignment::kCenter), gfx::RectF(100, 150, 100, 100), false); container.AddSnapAreaData(area); - gfx::ScrollOffset current_position(0, 0); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, + true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(40, snap_position.x()); EXPECT_EQ(40, snap_position.y()); } @@ -47,10 +52,12 @@ TEST_F(ScrollSnapDataTest, EndAlignmentCalculation) { SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd), gfx::RectF(150, 200, 100, 100), false); container.AddSnapAreaData(area); - gfx::ScrollOffset current_position(0, 0); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, + true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(40, snap_position.x()); EXPECT_EQ(90, snap_position.y()); } @@ -62,10 +69,12 @@ TEST_F(ScrollSnapDataTest, UnreachableSnapPositionCalculation) { SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd, SnapAlignment::kStart), gfx::RectF(200, 0, 100, 100), false); container.AddSnapAreaData(area); - gfx::ScrollOffset current_position(50, 50); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(50, 50), + true, true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); // Aligning to start on x would lead the scroll offset larger than max, and // aligning to end on y would lead the scroll offset smaller than zero. So // we expect these are clamped. @@ -85,13 +94,15 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) { gfx::RectF(0, 70, 150, 150), false); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(50, 150, 150, 150), false); - gfx::ScrollOffset current_position(100, 100); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); container.AddSnapAreaData(snap_on_both); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), + true, true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(80, snap_position.x()); EXPECT_EQ(70, snap_position.y()); } @@ -108,13 +119,15 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) { gfx::RectF(0, 70, 150, 150), false); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(50, 150, 150, 150), false); - gfx::ScrollOffset current_position(40, 120); + container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); container.AddSnapAreaData(snap_on_both); gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(40, 120), + true, true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(50, snap_position.x()); EXPECT_EQ(150, snap_position.y()); } @@ -129,12 +142,14 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) { SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(0, 70, 150, 150), false); - gfx::ScrollOffset current_position(100, 100); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); + gfx::ScrollOffset snap_position; - EXPECT_TRUE(container.FindSnapPosition(current_position, true, false, - &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), + true, false); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(80, snap_position.x()); EXPECT_EQ(100, snap_position.y()); } @@ -149,19 +164,20 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonVisibleAreas) { SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(400, 300, 100, 100), false); - gfx::ScrollOffset current_position(0, 0); + container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); gfx::ScrollOffset snap_position; - EXPECT_FALSE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, + true); + EXPECT_FALSE(container.FindSnapPosition(*strategy, &snap_position)); } TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) { SnapContainerData container( ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); - gfx::ScrollOffset current_position(0, 0); // Both the areas are currently visible. // However, if we snap to them on x and y independently, none is visible after @@ -180,9 +196,12 @@ TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) { container.AddSnapAreaData(snap_x); container.AddSnapAreaData(snap_y1); container.AddSnapAreaData(snap_y2); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, + true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); EXPECT_EQ(150, snap_position.x()); EXPECT_EQ(80, snap_position.y()); } @@ -193,13 +212,15 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapToPositionsOutsideProximityRange) { gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); container.set_proximity_range(gfx::ScrollOffset(50, 50)); - gfx::ScrollOffset current_position(100, 100); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(80, 160, 100, 100), false); container.AddSnapAreaData(area); + gfx::ScrollOffset snap_position; - EXPECT_TRUE( - container.FindSnapPosition(current_position, true, true, &snap_position)); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), + true, true); + EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); // The snap position on x, 80, is within the proximity range of [50, 150]. // However, the snap position on y, 160, is outside the proximity range of diff --git a/chromium/cc/input/snap_fling_controller.h b/chromium/cc/input/snap_fling_controller.h index 20f305651c2..eb07106796c 100644 --- a/chromium/cc/input/snap_fling_controller.h +++ b/chromium/cc/input/snap_fling_controller.h @@ -24,8 +24,8 @@ class SnapFlingCurve; class SnapFlingClient { public: virtual bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement, - gfx::Vector2dF* out_initial_offset, - gfx::Vector2dF* out_target_offset) const = 0; + gfx::Vector2dF* out_initial_position, + gfx::Vector2dF* out_target_position) const = 0; virtual gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) = 0; virtual void ScrollEndForSnapFling() = 0; virtual void RequestAnimationForSnapFling() = 0; diff --git a/chromium/cc/input/snap_selection_strategy.cc b/chromium/cc/input/snap_selection_strategy.cc new file mode 100644 index 00000000000..ce0f2655ecf --- /dev/null +++ b/chromium/cc/input/snap_selection_strategy.cc @@ -0,0 +1,151 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/input/snap_selection_strategy.h" + +namespace cc { + +std::unique_ptr<SnapSelectionStrategy> +SnapSelectionStrategy::CreateForEndPosition( + const gfx::ScrollOffset& current_position, + bool scrolled_x, + bool scrolled_y) { + return std::make_unique<EndPositionStrategy>(current_position, scrolled_x, + scrolled_y); +} + +std::unique_ptr<SnapSelectionStrategy> +SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset current_position, + gfx::ScrollOffset step) { + return std::make_unique<DirectionStrategy>(current_position, step); +} + +std::unique_ptr<SnapSelectionStrategy> +SnapSelectionStrategy::CreateForEndAndDirection( + gfx::ScrollOffset current_position, + gfx::ScrollOffset displacement) { + return std::make_unique<EndAndDirectionStrategy>(current_position, + displacement); +} + +bool EndPositionStrategy::ShouldSnapOnX() const { + return scrolled_x_; +} + +bool EndPositionStrategy::ShouldSnapOnY() const { + return scrolled_y_; +} + +gfx::ScrollOffset EndPositionStrategy::intended_position() const { + return current_position_; +} + +gfx::ScrollOffset EndPositionStrategy::base_position() const { + return current_position_; +} + +// |position| is unused in this method. +bool EndPositionStrategy::IsValidSnapPosition(SearchAxis axis, + float position) const { + return (scrolled_x_ && axis == SearchAxis::kX) || + (scrolled_y_ && axis == SearchAxis::kY); +} + +const base::Optional<SnapSearchResult>& EndPositionStrategy::PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const { + return covering.has_value() ? covering : closest; +} + +bool DirectionStrategy::ShouldSnapOnX() const { + return step_.x() != 0; +} + +bool DirectionStrategy::ShouldSnapOnY() const { + return step_.y() != 0; +} + +gfx::ScrollOffset DirectionStrategy::intended_position() const { + return current_position_ + step_; +} + +gfx::ScrollOffset DirectionStrategy::base_position() const { + return current_position_; +} + +bool DirectionStrategy::IsValidSnapPosition(SearchAxis axis, + float position) const { + if (axis == SearchAxis::kX) { + return (step_.x() > 0 && + position > current_position_.x()) || // "Right" arrow + (step_.x() < 0 && position < current_position_.x()); // "Left" arrow + } else { + return (step_.y() > 0 && + position > current_position_.y()) || // "Down" arrow + (step_.y() < 0 && position < current_position_.y()); // "Up" arrow + } +} + +const base::Optional<SnapSearchResult>& DirectionStrategy::PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const { + // We choose the |closest| result only if the default landing position (using + // the default step) is not a valid snap position (not making a snap area + // covering the snapport), or the |closest| is closer than the default landing + // position. + if (!closest.has_value()) + return covering; + if (!covering.has_value()) + return closest; + + // "Right" or "Down" arrow. + if ((step_.x() > 0 || step_.y() > 0) && + closest.value().snap_offset() < covering.value().snap_offset()) { + return closest; + } + // "Left" or "Up" arrow. + if ((step_.x() < 0 || step_.y() < 0) && + closest.value().snap_offset() > covering.value().snap_offset()) { + return closest; + } + + return covering; +} + +bool EndAndDirectionStrategy::ShouldSnapOnX() const { + return displacement_.x() != 0; +} + +bool EndAndDirectionStrategy::ShouldSnapOnY() const { + return displacement_.y() != 0; +} + +gfx::ScrollOffset EndAndDirectionStrategy::intended_position() const { + return current_position_ + displacement_; +} + +gfx::ScrollOffset EndAndDirectionStrategy::base_position() const { + return current_position_ + displacement_; +} + +bool EndAndDirectionStrategy::IsValidSnapPosition(SearchAxis axis, + float position) const { + if (axis == SearchAxis::kX) { + return (displacement_.x() > 0 && + position > current_position_.x()) || // Right + (displacement_.x() < 0 && position < current_position_.x()); // Left + } else { + return (displacement_.y() > 0 && + position > current_position_.y()) || // Down + (displacement_.y() < 0 && position < current_position_.y()); // Up + } +} + +const base::Optional<SnapSearchResult>& EndAndDirectionStrategy::PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const { + return covering.has_value() ? covering : closest; +} + +} // namespace cc diff --git a/chromium/cc/input/snap_selection_strategy.h b/chromium/cc/input/snap_selection_strategy.h new file mode 100644 index 00000000000..cebc63e96b5 --- /dev/null +++ b/chromium/cc/input/snap_selection_strategy.h @@ -0,0 +1,170 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_INPUT_SNAP_SELECTION_STRATEGY_H_ +#define CC_INPUT_SNAP_SELECTION_STRATEGY_H_ + +#include "scroll_snap_data.h" + +#include <memory> + +namespace cc { + +// This class represents an abstract strategy that decide which snap selection +// should be considered valid. There are concrete implementations for three core +// scrolling types: scroll with end position only, scroll with direction only, +// and scroll with end position and direction. +class CC_EXPORT SnapSelectionStrategy { + public: + SnapSelectionStrategy() = default; + virtual ~SnapSelectionStrategy() = default; + static std::unique_ptr<SnapSelectionStrategy> CreateForEndPosition( + const gfx::ScrollOffset& current_position, + bool scrolled_x, + bool scrolled_y); + static std::unique_ptr<SnapSelectionStrategy> CreateForDirection( + gfx::ScrollOffset current_position, + gfx::ScrollOffset step); + static std::unique_ptr<SnapSelectionStrategy> CreateForEndAndDirection( + gfx::ScrollOffset current_position, + gfx::ScrollOffset displacement); + + // Returns whether it's snappable on x or y depending on the scroll performed. + virtual bool ShouldSnapOnX() const = 0; + virtual bool ShouldSnapOnY() const = 0; + + // Returns the end position of the scroll if no snap interferes. + virtual gfx::ScrollOffset intended_position() const = 0; + // Returns the scroll position from which the snap position should minimize + // its distance. + virtual gfx::ScrollOffset base_position() const = 0; + // Returns the current scroll position of the snap container. + const gfx::ScrollOffset& current_position() const { + return current_position_; + } + + // Returns true if the selection strategy considers the given snap offset + // valid for the current axis. + virtual bool IsValidSnapPosition(SearchAxis axis, float position) const = 0; + + // Returns the best result according to snap selection strategy. This method + // is called at the end of selection process to make the final decision. + // + // -closest: snap search result representing closest match. + // -covering: snap search result representing the original target if it makes + // a snaparea covering the snapport. + virtual const base::Optional<SnapSearchResult>& PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const = 0; + + protected: + explicit SnapSelectionStrategy(const gfx::ScrollOffset& current_position) + : current_position_(current_position) {} + const gfx::ScrollOffset current_position_; +}; + +// Examples for intended end position scrolls include +// - a panning gesture, released without momentum +// - manupulating the scrollbar "thumb" explicitly +// - programmatically scrolling via APIs such as scrollTo() +// - tabbing through the document's focusable elements +// - navigating to an anchor within the page +// - homing operations such as the Home/End keys +// For this type of scrolls, we want to +// * Minimize the distance between the snap position and the end position. +// * Return the end position if that makes a snap area covers the snapport. +class EndPositionStrategy : public SnapSelectionStrategy { + public: + EndPositionStrategy(const gfx::ScrollOffset& current_position, + bool scrolled_x, + bool scrolled_y) + : SnapSelectionStrategy(current_position), + scrolled_x_(scrolled_x), + scrolled_y_(scrolled_y) {} + ~EndPositionStrategy() override = default; + + bool ShouldSnapOnX() const override; + bool ShouldSnapOnY() const override; + + gfx::ScrollOffset intended_position() const override; + gfx::ScrollOffset base_position() const override; + + bool IsValidSnapPosition(SearchAxis axis, float position) const override; + + const base::Optional<SnapSearchResult>& PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const override; + + private: + // Whether the x axis and y axis have been scrolled in this scroll gesture. + const bool scrolled_x_; + const bool scrolled_y_; +}; + +// Examples for intended direction scrolls include +// - pressing an arrow key on the keyboard +// - a swiping gesture interpreted as a fixed (rather than inertial) scroll +// For this type of scrolls, we want to +// * Minimize the distance between the snap position and the starting position, +// so that we stop at the first snap position in that direction. +// * Return the default intended position (using the default step) if that makes +// a snap area covers the snapport. +class DirectionStrategy : public SnapSelectionStrategy { + public: + DirectionStrategy(const gfx::ScrollOffset& current_position, + const gfx::ScrollOffset& step) + : SnapSelectionStrategy(current_position), step_(step) {} + ~DirectionStrategy() override = default; + + bool ShouldSnapOnX() const override; + bool ShouldSnapOnY() const override; + + gfx::ScrollOffset intended_position() const override; + gfx::ScrollOffset base_position() const override; + + bool IsValidSnapPosition(SearchAxis axis, float position) const override; + + const base::Optional<SnapSearchResult>& PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const override; + + private: + // The default step for this DirectionStrategy. + const gfx::ScrollOffset step_; +}; + +// Examples for intended direction and end position scrolls include +// - a “fling” gesture, interpreted with momentum +// - programmatically scrolling via APIs such as scrollBy() +// - paging operations such as the PgUp/PgDn keys (or equivalent operations on +// the scrollbar) +// For this type of scrolls, we want to +// * Minimize the distance between the snap position and the end position. +// * Return the end position if that makes a snap area covers the snapport. +class EndAndDirectionStrategy : public SnapSelectionStrategy { + public: + EndAndDirectionStrategy(const gfx::ScrollOffset& current_position, + const gfx::ScrollOffset& displacement) + : SnapSelectionStrategy(current_position), displacement_(displacement) {} + ~EndAndDirectionStrategy() override = default; + + bool ShouldSnapOnX() const override; + bool ShouldSnapOnY() const override; + + gfx::ScrollOffset intended_position() const override; + gfx::ScrollOffset base_position() const override; + + bool IsValidSnapPosition(SearchAxis axis, float position) const override; + + const base::Optional<SnapSearchResult>& PickBestResult( + const base::Optional<SnapSearchResult>& closest, + const base::Optional<SnapSearchResult>& covering) const override; + + private: + const gfx::ScrollOffset displacement_; +}; + +} // namespace cc + +#endif // CC_INPUT_SNAP_SELECTION_STRATEGY_H_ diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc index e8cd98328ae..1837ed16487 100644 --- a/chromium/cc/layers/heads_up_display_layer.cc +++ b/chromium/cc/layers/heads_up_display_layer.cc @@ -8,6 +8,7 @@ #include "base/trace_event/trace_event.h" #include "cc/layers/heads_up_display_layer_impl.h" +#include "cc/trees/layer_tree_host.h" namespace cc { @@ -27,6 +28,32 @@ HeadsUpDisplayLayer::HeadsUpDisplayLayer() HeadsUpDisplayLayer::~HeadsUpDisplayLayer() = default; +void HeadsUpDisplayLayer::UpdateLocationAndSize( + const gfx::Size& device_viewport, + float device_scale_factor) { + gfx::Size device_viewport_in_layout_pixels = + gfx::Size(device_viewport.width() / device_scale_factor, + device_viewport.height() / device_scale_factor); + + gfx::Size bounds; + gfx::Transform matrix; + matrix.MakeIdentity(); + + if (layer_tree_host()->GetDebugState().ShowHudRects()) { + bounds = device_viewport_in_layout_pixels; + } else { + // If the HUD is not displaying full-viewport rects (e.g., it is showing the + // FPS meter), use a fixed size. + constexpr int kDefaultHUDSize = 256; + bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize); + matrix.Translate(device_viewport_in_layout_pixels.width() - kDefaultHUDSize, + 0.0); + } + + SetBounds(bounds); + SetTransform(matrix); +} + bool HeadsUpDisplayLayer::HasDrawableContent() const { return true; } diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h index ee3402e67c2..2936a975c80 100644 --- a/chromium/cc/layers/heads_up_display_layer.h +++ b/chromium/cc/layers/heads_up_display_layer.h @@ -20,6 +20,9 @@ class CC_EXPORT HeadsUpDisplayLayer : public Layer { public: static scoped_refptr<HeadsUpDisplayLayer> Create(); + void UpdateLocationAndSize(const gfx::Size& device_viewport, + float device_scale_factor); + std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; // Layer overrides. diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index ee4a8ff3813..cb7ee65c26e 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -11,13 +11,19 @@ #include <vector> #include "base/numerics/safe_conversions.h" +#include "base/optional.h" #include "base/single_thread_task_runner.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/debug/debug_colors.h" +#include "cc/paint/display_item_list.h" +#include "cc/paint/paint_canvas.h" +#include "cc/paint/paint_flags.h" +#include "cc/paint/paint_shader.h" +#include "cc/paint/record_paint_canvas.h" +#include "cc/paint/skia_paint_canvas.h" #include "cc/raster/scoped_gpu_raster.h" #include "cc/resources/memory_history.h" #include "cc/trees/frame_rate_counter.h" @@ -33,42 +39,54 @@ #include "components/viz/common/resources/platform_color.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/command_buffer/client/raster_interface.h" #include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" -#include "skia/ext/platform_canvas.h" -#include "third_party/skia/include/core/SkCanvas.h" +#include "gpu/config/gpu_feature_info.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "third_party/skia/include/core/SkFont.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/effects/SkColorMatrixFilter.h" -#include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/skia_util.h" #include "ui/gl/trace_util.h" namespace cc { -static inline SkPaint CreatePaint() { - SkPaint paint; -#if (SK_R32_SHIFT || SK_B32_SHIFT != 16) - // The SkCanvas is in RGBA but the shader is expecting BGRA, so we need to - // swizzle our colors when drawing to the SkCanvas. - SkScalar color_matrix[20]; - for (int i = 0; i < 20; ++i) - color_matrix[i] = 0; - color_matrix[0 + 5 * 2] = 1; - color_matrix[1 + 5 * 1] = 1; - color_matrix[2 + 5 * 0] = 1; - color_matrix[3 + 5 * 3] = 1; - - paint.setColorFilter( - SkColorFilter::MakeMatrixFilterRowMajor255(color_matrix)); -#endif - return paint; +namespace { + +void DrawArc(PaintCanvas* canvas, + const SkRect& oval, + SkScalar start_angle, + SkScalar sweep_angle, + const PaintFlags& flags) { + DCHECK_GT(sweep_angle, 0.f); + DCHECK_LT(sweep_angle, 360.f); + SkPath path; + path.moveTo(oval.centerX(), oval.centerY()); + path.arcTo(oval, start_angle, sweep_angle, false /* forceMoveTo */); + path.close(); + canvas->drawPath(path, flags); } +class DummyImageProvider : public ImageProvider { + public: + DummyImageProvider() = default; + ~DummyImageProvider() override = default; + ScopedDecodedDrawImage GetDecodedDrawImage( + const DrawImage& draw_image) override { + NOTREACHED(); + return ScopedDecodedDrawImage(); + } +}; + +} // namespace + HeadsUpDisplayLayerImpl::Graph::Graph(double indicator_value, double start_upper_bound) : value(0.0), @@ -90,7 +108,9 @@ HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl, internal_contents_scale_(1.f), fps_graph_(60.0, 80.0), paint_time_graph_(16.0, 48.0), - fade_step_(0) {} + fade_step_(0), + raster_color_space_(gfx::ColorSpace::CreateSRGB(), + gfx::ColorSpace::GetNextId()) {} HeadsUpDisplayLayerImpl::~HeadsUpDisplayLayerImpl() { ReleaseResources(); @@ -106,11 +126,10 @@ class HudGpuBacking : public ResourcePool::GpuBacking { ~HudGpuBacking() override { if (mailbox.IsZero()) return; - auto* sii = compositor_context_provider->SharedImageInterface(); if (returned_sync_token.HasData()) - sii->DestroySharedImage(returned_sync_token, mailbox); + shared_image_interface->DestroySharedImage(returned_sync_token, mailbox); else if (mailbox_sync_token.HasData()) - sii->DestroySharedImage(mailbox_sync_token, mailbox); + shared_image_interface->DestroySharedImage(mailbox_sync_token, mailbox); } void OnMemoryDump( @@ -126,7 +145,7 @@ class HudGpuBacking : public ResourcePool::GpuBacking { pmd->AddOwnershipEdge(buffer_dump_guid, tracing_guid, importance); } - viz::ContextProvider* compositor_context_provider; + gpu::SharedImageInterface* shared_image_interface = nullptr; }; class HudSoftwareBacking : public ResourcePool::SoftwareBacking { @@ -198,14 +217,33 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( // Update state that will be drawn. UpdateHudContents(); + // TODO(penghuang): Do not use worker_context_provider() when context_provider + // is changed to RasterContextProvider. + // https://crbug.com/c/1286950 + auto* raster_context_provider = + gpu_raster ? layer_tree_frame_sink->worker_context_provider() : nullptr; + base::Optional<viz::RasterContextProvider::ScopedRasterContextLock> lock; + bool use_oopr = false; + if (raster_context_provider) { + lock.emplace(raster_context_provider); + use_oopr = raster_context_provider->GetGpuFeatureInfo() + .status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] == + gpu::kGpuFeatureStatusEnabled; + if (!use_oopr) { + raster_context_provider = nullptr; + lock.reset(); + } + } + + auto* context_provider = layer_tree_frame_sink->context_provider(); if (!pool_) { scoped_refptr<base::SingleThreadTaskRunner> task_runner = layer_tree_impl()->task_runner_provider()->HasImplThread() ? layer_tree_impl()->task_runner_provider()->ImplThreadTaskRunner() : layer_tree_impl()->task_runner_provider()->MainThreadTaskRunner(); pool_ = std::make_unique<ResourcePool>( - resource_provider, layer_tree_frame_sink->context_provider(), - std::move(task_runner), ResourcePool::kDefaultExpirationDelay, + resource_provider, context_provider, std::move(task_runner), + ResourcePool::kDefaultExpirationDelay, layer_tree_impl()->settings().disallow_non_exact_resource_reuse); } @@ -220,39 +258,58 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( // compositing. ResourcePool::InUsePoolResource pool_resource; if (draw_mode == DRAW_MODE_HARDWARE) { - viz::ContextProvider* context_provider = - layer_tree_impl()->context_provider(); - DCHECK(context_provider); - + DCHECK(raster_context_provider || context_provider); + const auto& caps = raster_context_provider + ? raster_context_provider->ContextCapabilities() + : context_provider->ContextCapabilities(); viz::ResourceFormat format = - viz::PlatformColor::BestSupportedRenderBufferFormat( - context_provider->ContextCapabilities()); + viz::PlatformColor::BestSupportedRenderBufferFormat(caps); pool_resource = pool_->AcquireResource(internal_content_bounds_, format, gfx::ColorSpace()); if (!pool_resource.gpu_backing()) { auto backing = std::make_unique<HudGpuBacking>(); - backing->compositor_context_provider = context_provider; + auto* sii = raster_context_provider + ? raster_context_provider->SharedImageInterface() + : context_provider->SharedImageInterface(); + backing->shared_image_interface = sii; backing->InitOverlayCandidateAndTextureTarget( - pool_resource.format(), context_provider->ContextCapabilities(), + pool_resource.format(), caps, layer_tree_impl() ->settings() .resource_settings.use_gpu_memory_buffer_resources); - auto* sii = context_provider->SharedImageInterface(); - uint32_t flags = gpu::SHARED_IMAGE_USAGE_GLES2; - if (gpu_raster) - flags |= gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT; + + uint32_t flags = 0; + if (use_oopr) { + flags = gpu::SHARED_IMAGE_USAGE_RASTER | + gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; + } else if (gpu_raster) { + flags = gpu::SHARED_IMAGE_USAGE_GLES2 | + gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT; + } if (backing->overlay_candidate) flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; backing->mailbox = sii->CreateSharedImage(pool_resource.format(), pool_resource.size(), pool_resource.color_space(), flags); - gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); - gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + if (raster_context_provider) { + auto* ri = raster_context_provider->RasterInterface(); + ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + } else { + auto* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + } pool_resource.set_gpu_backing(std::move(backing)); } else if (pool_resource.gpu_backing()->returned_sync_token.HasData()) { - context_provider->ContextGL()->WaitSyncTokenCHROMIUM( - pool_resource.gpu_backing()->returned_sync_token.GetConstData()); + if (raster_context_provider) { + auto* ri = raster_context_provider->RasterInterface(); + ri->WaitSyncTokenCHROMIUM( + pool_resource.gpu_backing()->returned_sync_token.GetConstData()); + } else { + auto* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM( + pool_resource.gpu_backing()->returned_sync_token.GetConstData()); + } pool_resource.gpu_backing()->returned_sync_token = gpu::SyncToken(); } } else { @@ -285,29 +342,60 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( DCHECK_EQ(draw_mode, DRAW_MODE_HARDWARE); DCHECK(pool_resource.gpu_backing()); auto* backing = static_cast<HudGpuBacking*>(pool_resource.gpu_backing()); - viz::ContextProvider* context_provider = - layer_tree_impl()->context_provider(); - gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); - GLuint mailbox_texture_id = - gl->CreateAndConsumeTextureCHROMIUM(backing->mailbox.name); - { - ScopedGpuRaster gpu_raster(context_provider); - viz::ClientResourceProvider::ScopedSkSurface scoped_surface( - context_provider->GrContext(), mailbox_texture_id, - backing->texture_target, pool_resource.size(), pool_resource.format(), - false /* can_use_lcd_text */, 0 /* msaa_sample_count */); - SkSurface* surface = scoped_surface.surface(); - if (!surface) { - pool_->ReleaseResource(std::move(pool_resource)); - return; + if (use_oopr) { + const auto& size = pool_resource.size(); + auto display_item_list = base::MakeRefCounted<DisplayItemList>( + DisplayItemList::kTopLevelDisplayItemList); + RecordPaintCanvas canvas(display_item_list.get(), + SkRect::MakeIWH(size.width(), size.height())); + display_item_list->StartPaint(); + DrawHudContents(&canvas); + display_item_list->EndPaintOfUnpaired(gfx::Rect(size)); + display_item_list->Finalize(); + + auto* ri = raster_context_provider->RasterInterface(); + constexpr GLuint background_color = SkColorSetARGB(0, 0, 0, 0); + constexpr GLuint msaa_sample_count = -1; + constexpr bool can_use_lcd_text = true; + const auto pixel_config = viz::ResourceFormatToClosestSkColorType( + true /* gpu_compositing */, pool_resource.format()); + ri->BeginRasterCHROMIUM(background_color, msaa_sample_count, + can_use_lcd_text, pixel_config, + raster_color_space_, backing->mailbox.name); + gfx::Vector2dF post_translate(0.f, 0.f); + DummyImageProvider image_provider; + ri->RasterCHROMIUM(display_item_list.get(), &image_provider, size, + gfx::Rect(size), gfx::Rect(size), post_translate, + 1.f /* post_scale */, false /* requires_clear */); + ri->EndRasterCHROMIUM(); + backing->mailbox_sync_token = + viz::ClientResourceProvider::GenerateSyncTokenHelper(ri); + } else { + auto* gl = context_provider->ContextGL(); + GLuint mailbox_texture_id = + gl->CreateAndConsumeTextureCHROMIUM(backing->mailbox.name); + + { + ScopedGpuRaster gpu_raster(context_provider); + viz::ClientResourceProvider::ScopedSkSurface scoped_surface( + context_provider->GrContext(), mailbox_texture_id, + backing->texture_target, pool_resource.size(), + pool_resource.format(), false /* can_use_lcd_text */, + 0 /* msaa_sample_count */); + SkSurface* surface = scoped_surface.surface(); + if (!surface) { + pool_->ReleaseResource(std::move(pool_resource)); + return; + } + SkiaPaintCanvas canvas(surface->getCanvas()); + DrawHudContents(&canvas); } - DrawHudContents(surface->getCanvas()); - } - gl->DeleteTextures(1, &mailbox_texture_id); - backing->mailbox_sync_token = - viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); + gl->DeleteTextures(1, &mailbox_texture_id); + backing->mailbox_sync_token = + viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); + } } else if (draw_mode == DRAW_MODE_HARDWARE) { // If not using |gpu_raster| but using gpu compositing, we DrawHudContents() // into a software bitmap and upload it to a texture for compositing. @@ -324,7 +412,8 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( pool_resource.size().width(), pool_resource.size().height()); } - DrawHudContents(staging_surface_->getCanvas()); + SkiaPaintCanvas canvas(staging_surface_->getCanvas()); + DrawHudContents(&canvas); TRACE_EVENT0("cc", "UploadHudTexture"); SkPixmap pixmap; @@ -333,10 +422,12 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( gl->CreateAndConsumeTextureCHROMIUM(backing->mailbox.name); gl->BindTexture(backing->texture_target, mailbox_texture_id); DCHECK(GLSupportsFormat(pool_resource.format())); + // We should use gl compatible format for skia SW rasterization. + constexpr GLenum format = SK_B32_SHIFT ? GL_RGBA : GL_BGRA_EXT; + constexpr GLenum type = GL_UNSIGNED_BYTE; gl->TexSubImage2D( backing->texture_target, 0, 0, 0, pool_resource.size().width(), - pool_resource.size().height(), GLDataFormat(pool_resource.format()), - GLDataType(pool_resource.format()), pixmap.addr()); + pool_resource.size().height(), format, type, pixmap.addr()); gl->DeleteTextures(1, &mailbox_texture_id); backing->mailbox_sync_token = viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); @@ -354,12 +445,14 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect( info, backing->shared_memory->memory(), info.minRowBytes()); - DrawHudContents(surface->getCanvas()); + SkiaPaintCanvas canvas(surface->getCanvas()); + DrawHudContents(&canvas); } // Exports the backing to the ResourceProvider, giving it a ResourceId that // can be used in a DrawQuad. - pool_->PrepareForExport(pool_resource); + bool exported = pool_->PrepareForExport(pool_resource); + DCHECK(exported); viz::ResourceId resource_id = pool_resource.resource_id_for_export(); // Save the resource to prevent reuse until it is exported to the display @@ -389,7 +482,8 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( /*uv_bottom_right=*/gfx::PointF(1.f, 1.f), /*background_color=*/SK_ColorTRANSPARENT, vertex_opacity, /*flipped=*/false, - /*nearest_neighbor=*/false, /*secure_output_only=*/false); + /*nearest_neighbor=*/false, /*secure_output_only=*/false, + ui::ProtectedVideoType::kClear); ValidateQuadResources(quad); break; } @@ -456,7 +550,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudContents() { paint_time_graph_.UpdateUpperBound(); } -void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) { +void HeadsUpDisplayLayerImpl::DrawHudContents(PaintCanvas* canvas) { const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state(); TRACE_EVENT0("cc", "DrawHudContents"); @@ -486,85 +580,74 @@ void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) { canvas->restore(); } -int HeadsUpDisplayLayerImpl::MeasureText(SkPaint* paint, - const std::string& text, - int size) const { - DCHECK(typeface_.get()); - const bool anti_alias = paint->isAntiAlias(); - paint->setAntiAlias(true); - paint->setTextSize(size); - paint->setTypeface(typeface_); - SkScalar text_width = paint->measureText(text.c_str(), text.length()); - - paint->setAntiAlias(anti_alias); - return SkScalarCeilToInt(text_width); -} -void HeadsUpDisplayLayerImpl::DrawText(SkCanvas* canvas, - SkPaint* paint, + +void HeadsUpDisplayLayerImpl::DrawText(PaintCanvas* canvas, + PaintFlags* flags, const std::string& text, - SkPaint::Align align, + TextAlign align, int size, int x, int y) const { DCHECK(typeface_.get()); - const bool anti_alias = paint->isAntiAlias(); - paint->setAntiAlias(true); - - paint->setTextSize(size); - paint->setTextAlign(align); - paint->setTypeface(typeface_); - canvas->drawText(text.c_str(), text.length(), x, y, *paint); + flags->setAntiAlias(true); + flags->setTextSize(size); + flags->setTypeface(typeface_); + if (align == TextAlign::kCenter) { + auto width = flags->ToSkPaint().measureText(text.c_str(), text.length()); + x -= width * 0.5f; + } else if (align == TextAlign::kRight) { + auto width = flags->ToSkPaint().measureText(text.c_str(), text.length()); + x -= width; + } + auto sk_paint = flags->ToSkPaint(); - paint->setAntiAlias(anti_alias); + auto text_blob = SkTextBlob::MakeFromText( + text.c_str(), text.length(), + SkFont(sk_paint.refTypeface(), sk_paint.getTextSize())); + canvas->drawTextBlob(std::move(text_blob), x, y, *flags); } -void HeadsUpDisplayLayerImpl::DrawText(SkCanvas* canvas, - SkPaint* paint, +void HeadsUpDisplayLayerImpl::DrawText(PaintCanvas* canvas, + PaintFlags* flags, const std::string& text, - SkPaint::Align align, + TextAlign align, int size, const SkPoint& pos) const { - DrawText(canvas, paint, text, align, size, pos.x(), pos.y()); + DrawText(canvas, flags, text, align, size, pos.x(), pos.y()); } -void HeadsUpDisplayLayerImpl::DrawGraphBackground(SkCanvas* canvas, - SkPaint* paint, +void HeadsUpDisplayLayerImpl::DrawGraphBackground(PaintCanvas* canvas, + PaintFlags* flags, const SkRect& bounds) const { - paint->setColor(DebugColors::HUDBackgroundColor()); - canvas->drawRect(bounds, *paint); + flags->setColor(DebugColors::HUDBackgroundColor()); + canvas->drawRect(bounds, *flags); } -void HeadsUpDisplayLayerImpl::DrawGraphLines(SkCanvas* canvas, - SkPaint* paint, +void HeadsUpDisplayLayerImpl::DrawGraphLines(PaintCanvas* canvas, + PaintFlags* flags, const SkRect& bounds, const Graph& graph) const { // Draw top and bottom line. - paint->setColor(DebugColors::HUDSeparatorLineColor()); - canvas->drawLine(bounds.left(), - bounds.top() - 1, - bounds.right(), - bounds.top() - 1, - *paint); - canvas->drawLine( - bounds.left(), bounds.bottom(), bounds.right(), bounds.bottom(), *paint); + flags->setColor(DebugColors::HUDSeparatorLineColor()); + canvas->drawLine(bounds.left(), bounds.top() - 1, bounds.right(), + bounds.top() - 1, *flags); + canvas->drawLine(bounds.left(), bounds.bottom(), bounds.right(), + bounds.bottom(), *flags); // Draw indicator line (additive blend mode to increase contrast when drawn on // top of graph). - paint->setColor(DebugColors::HUDIndicatorLineColor()); - paint->setBlendMode(SkBlendMode::kPlus); + flags->setColor(DebugColors::HUDIndicatorLineColor()); + flags->setBlendMode(SkBlendMode::kPlus); const double indicator_top = bounds.height() * (1.0 - graph.indicator / graph.current_upper_bound) - 1.0; - canvas->drawLine(bounds.left(), - bounds.top() + indicator_top, - bounds.right(), - bounds.top() + indicator_top, - *paint); - paint->setBlendMode(SkBlendMode::kSrcOver); + canvas->drawLine(bounds.left(), bounds.top() + indicator_top, bounds.right(), + bounds.top() + indicator_top, *flags); + flags->setBlendMode(SkBlendMode::kSrcOver); } SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( - SkCanvas* canvas, + PaintCanvas* canvas, const FrameRateCounter* fps_counter, int right, int top) const { @@ -585,8 +668,8 @@ SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( int left = bounds().width() - width - right; SkRect area = SkRect::MakeXYWH(left, top, width, height); - SkPaint paint = CreatePaint(); - DrawGraphBackground(canvas, &paint, area); + PaintFlags flags; + DrawGraphBackground(canvas, &flags, area); SkRect title_bounds = SkRect::MakeXYWH( left + kPadding, top + kPadding, kGraphWidth + kHistogramWidth + kGap + 2, @@ -594,14 +677,12 @@ SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( SkRect text_bounds = SkRect::MakeXYWH(left + kPadding, title_bounds.bottom() + 2 * kPadding, kGraphWidth + kHistogramWidth + kGap + 2, kFontHeight); - SkRect graph_bounds = SkRect::MakeXYWH(left + kPadding, - text_bounds.bottom() + 2 * kPadding, - kGraphWidth, - kGraphHeight); - SkRect histogram_bounds = SkRect::MakeXYWH(graph_bounds.right() + kGap, - graph_bounds.top(), - kHistogramWidth, - kGraphHeight); + SkRect graph_bounds = + SkRect::MakeXYWH(left + kPadding, text_bounds.bottom() + 2 * kPadding, + kGraphWidth, kGraphHeight); + SkRect histogram_bounds = + SkRect::MakeXYWH(graph_bounds.right() + kGap, graph_bounds.top(), + kHistogramWidth, kGraphHeight); const std::string title("Frame Rate"); const std::string value_text = @@ -611,33 +692,23 @@ SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( VLOG(1) << value_text; - paint.setColor(DebugColors::HUDTitleColor()); - DrawText(canvas, &paint, title, SkPaint::kLeft_Align, kTitleFontHeight, + flags.setColor(DebugColors::HUDTitleColor()); + DrawText(canvas, &flags, title, TextAlign::kLeft, kTitleFontHeight, title_bounds.left(), title_bounds.bottom()); - paint.setColor(DebugColors::FPSDisplayTextAndGraphColor()); - DrawText(canvas, - &paint, - value_text, - SkPaint::kLeft_Align, - kFontHeight, - text_bounds.left(), - text_bounds.bottom()); - DrawText(canvas, - &paint, - min_max_text, - SkPaint::kRight_Align, - kFontHeight, - text_bounds.right(), - text_bounds.bottom()); - - DrawGraphLines(canvas, &paint, graph_bounds, fps_graph_); + flags.setColor(DebugColors::FPSDisplayTextAndGraphColor()); + DrawText(canvas, &flags, value_text, TextAlign::kLeft, kFontHeight, + text_bounds.left(), text_bounds.bottom()); + DrawText(canvas, &flags, min_max_text, TextAlign::kRight, kFontHeight, + text_bounds.right(), text_bounds.bottom()); + + DrawGraphLines(canvas, &flags, graph_bounds, fps_graph_); // Collect graph and histogram data. SkPath path; const int kHistogramSize = 20; - double histogram[kHistogramSize] = { 1.0 }; + double histogram[kHistogramSize] = {1.0}; double max_bucket_value = 1.0; for (FrameRateCounter::RingBufferType::Iterator it = --fps_counter->end(); it; @@ -674,19 +745,15 @@ SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( } // Draw FPS histogram. - paint.setColor(DebugColors::HUDSeparatorLineColor()); - canvas->drawLine(histogram_bounds.left() - 1, - histogram_bounds.top() - 1, - histogram_bounds.left() - 1, - histogram_bounds.bottom() + 1, - paint); - canvas->drawLine(histogram_bounds.right() + 1, - histogram_bounds.top() - 1, - histogram_bounds.right() + 1, - histogram_bounds.bottom() + 1, - paint); - - paint.setColor(DebugColors::FPSDisplayTextAndGraphColor()); + flags.setColor(DebugColors::HUDSeparatorLineColor()); + canvas->drawLine(histogram_bounds.left() - 1, histogram_bounds.top() - 1, + histogram_bounds.left() - 1, histogram_bounds.bottom() + 1, + flags); + canvas->drawLine(histogram_bounds.right() + 1, histogram_bounds.top() - 1, + histogram_bounds.right() + 1, histogram_bounds.bottom() + 1, + flags); + + flags.setColor(DebugColors::FPSDisplayTextAndGraphColor()); const double bar_height = histogram_bounds.height() / kHistogramSize; for (int i = kHistogramSize - 1; i >= 0; --i) { @@ -696,22 +763,21 @@ SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( canvas->drawRect( SkRect::MakeXYWH(histogram_bounds.left(), histogram_bounds.bottom() - (i + 1) * bar_height, - bar_width, - 1), - paint); + bar_width, 1), + flags); } } // Draw FPS graph. - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(1); - canvas->drawPath(path, paint); + flags.setAntiAlias(true); + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(1); + canvas->drawPath(path, flags); return area; } -SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas, +SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(PaintCanvas* canvas, int right, int top, int width) const { @@ -725,8 +791,8 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas, const double kMegabyte = 1024.0 * 1024.0; - SkPaint paint = CreatePaint(); - DrawGraphBackground(canvas, &paint, area); + PaintFlags flags; + DrawGraphBackground(canvas, &flags, area); SkPoint title_pos = SkPoint::Make(left + kPadding, top + kFontHeight + kPadding); @@ -735,31 +801,32 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas, SkPoint stat2_pos = SkPoint::Make(left + width - kPadding - 1, top + 2 * kPadding + 3 * kFontHeight); - paint.setColor(DebugColors::HUDTitleColor()); - DrawText(canvas, &paint, "GPU Memory", SkPaint::kLeft_Align, kTitleFontHeight, + flags.setColor(DebugColors::HUDTitleColor()); + DrawText(canvas, &flags, "GPU Memory", TextAlign::kLeft, kTitleFontHeight, title_pos); - paint.setColor(DebugColors::MemoryDisplayTextColor()); + flags.setColor(DebugColors::MemoryDisplayTextColor()); std::string text = base::StringPrintf( "%6.1f MB used", memory_entry_.total_bytes_used / kMegabyte); - DrawText(canvas, &paint, text, SkPaint::kRight_Align, kFontHeight, stat1_pos); + DrawText(canvas, &flags, text, TextAlign::kRight, kFontHeight, stat1_pos); if (!memory_entry_.had_enough_memory) - paint.setColor(SK_ColorRED); + flags.setColor(SK_ColorRED); text = base::StringPrintf("%6.1f MB max ", memory_entry_.total_budget_in_bytes / kMegabyte); - DrawText(canvas, &paint, text, SkPaint::kRight_Align, kFontHeight, stat2_pos); + + DrawText(canvas, &flags, text, TextAlign::kRight, kFontHeight, stat2_pos); // Draw memory graph. int length = 2 * kFontHeight + kPadding + 12; SkRect oval = SkRect::MakeXYWH(left + kPadding * 6, top + kTitleFontHeight + kPadding * 3, length, length); - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kFill_Style); + flags.setAntiAlias(true); + flags.setStyle(PaintFlags::kFill_Style); - paint.setColor(SkColorSetARGB(64, 255, 255, 0)); - canvas->drawArc(oval, 180, 180, true, paint); + flags.setColor(SkColorSetARGB(64, 255, 255, 0)); + DrawArc(canvas, oval, 180, 180, flags); int radius = length / 2; int cx = oval.left() + radius; @@ -773,24 +840,25 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas, const SkScalar pos[] = {SkFloatToScalar(0.2f), SkFloatToScalar(0.4f), SkFloatToScalar(0.6f), SkFloatToScalar(0.8f), SkFloatToScalar(1.0f)}; - paint.setShader(SkGradientShader::MakeSweep(cx, cy, colors, pos, 5)); - paint.setFlags(SkPaint::kAntiAlias_Flag); + flags.setShader(PaintShader::MakeSweepGradient( + cx, cy, colors, pos, 5, SkShader::kClamp_TileMode, 0, 360)); + flags.setAntiAlias(true); // Draw current status. - paint.setStyle(SkPaint::kStroke_Style); - paint.setAlpha(32); - paint.setStrokeWidth(4); - canvas->drawArc(oval, 180, angle, true, paint); + flags.setStyle(PaintFlags::kStroke_Style); + flags.setAlpha(32); + flags.setStrokeWidth(4); + DrawArc(canvas, oval, 180, angle, flags); - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(SkColorSetARGB(255, 0, 255, 0)); - canvas->drawArc(oval, 180, angle, true, paint); - paint.setShader(nullptr); + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(SkColorSetARGB(255, 0, 255, 0)); + DrawArc(canvas, oval, 180, angle, flags); + flags.setShader(nullptr); return area; } -SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas, +SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(PaintCanvas* canvas, int right, int top, int width) const { @@ -830,24 +898,24 @@ SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas, const int left = bounds().width() - width - right; const SkRect area = SkRect::MakeXYWH(left, top, width, height); - SkPaint paint = CreatePaint(); - DrawGraphBackground(canvas, &paint, area); + PaintFlags flags; + DrawGraphBackground(canvas, &flags, area); SkPoint gpu_status_pos = SkPoint::Make(left + width - kPadding, top + 2 * kFontHeight + 2 * kPadding); - paint.setColor(DebugColors::HUDTitleColor()); - DrawText(canvas, &paint, "GPU Raster", SkPaint::kLeft_Align, kTitleFontHeight, + flags.setColor(DebugColors::HUDTitleColor()); + DrawText(canvas, &flags, "GPU Raster", TextAlign::kLeft, kTitleFontHeight, left + kPadding, top + kFontHeight + kPadding); - paint.setColor(color); - DrawText(canvas, &paint, status, SkPaint::kRight_Align, kFontHeight, + flags.setColor(color); + DrawText(canvas, &flags, status, TextAlign::kRight, kFontHeight, gpu_status_pos); return area; } void HeadsUpDisplayLayerImpl::DrawDebugRect( - SkCanvas* canvas, - SkPaint* paint, + PaintCanvas* canvas, + PaintFlags* flags, const DebugRect& rect, SkColor stroke_color, SkColor fill_color, @@ -858,14 +926,14 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect( gfx::ScaleToEnclosingRect(rect.rect, 1.0 / internal_contents_scale_, 1.0 / internal_contents_scale_); SkIRect sk_rect = RectToSkIRect(debug_layer_rect); - paint->setColor(fill_color); - paint->setStyle(SkPaint::kFill_Style); - canvas->drawIRect(sk_rect, *paint); + flags->setColor(fill_color); + flags->setStyle(PaintFlags::kFill_Style); + canvas->drawIRect(sk_rect, *flags); - paint->setColor(stroke_color); - paint->setStyle(SkPaint::kStroke_Style); - paint->setStrokeWidth(SkFloatToScalar(stroke_width)); - canvas->drawIRect(sk_rect, *paint); + flags->setColor(stroke_color); + flags->setStyle(PaintFlags::kStroke_Style); + flags->setStrokeWidth(SkFloatToScalar(stroke_width)); + canvas->drawIRect(sk_rect, *flags); if (label_text.length()) { const int kFontHeight = 12; @@ -881,33 +949,29 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect( canvas->clipRect(sk_clip_rect); canvas->translate(sk_clip_rect.x(), sk_clip_rect.y()); - SkPaint label_paint = CreatePaint(); - label_paint.setTextSize(kFontHeight); - label_paint.setTypeface(typeface_); - label_paint.setColor(stroke_color); + PaintFlags label_flags; + label_flags.setTextSize(kFontHeight); + label_flags.setTypeface(typeface_); + label_flags.setColor(stroke_color); - const SkScalar label_text_width = - label_paint.measureText(label_text.c_str(), label_text.length()); + const SkScalar label_text_width = label_flags.ToSkPaint().measureText( + label_text.c_str(), label_text.length()); canvas->drawRect(SkRect::MakeWH(label_text_width + 2 * kPadding, kFontHeight + 2 * kPadding), - label_paint); - - label_paint.setAntiAlias(true); - label_paint.setColor(SkColorSetARGB(255, 50, 50, 50)); - canvas->drawText(label_text.c_str(), - label_text.length(), - kPadding, - kFontHeight * 0.8f + kPadding, - label_paint); + label_flags); + label_flags.setAntiAlias(true); + label_flags.setColor(SkColorSetARGB(255, 50, 50, 50)); + DrawText(canvas, &label_flags, label_text, TextAlign::kLeft, kFontHeight, + kPadding, kFontHeight * 0.8f + kPadding); canvas->restore(); } } void HeadsUpDisplayLayerImpl::DrawDebugRects( - SkCanvas* canvas, + PaintCanvas* canvas, DebugRectHistory* debug_rect_history) { - SkPaint paint = CreatePaint(); + PaintFlags flags; const std::vector<DebugRect>& debug_rects = debug_rect_history->debug_rects(); std::vector<DebugRect> new_paint_rects; @@ -970,13 +1034,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( break; } - DrawDebugRect(canvas, - &paint, - debug_rects[i], - stroke_color, - fill_color, - stroke_width, - label_text); + DrawDebugRect(canvas, &flags, debug_rects[i], stroke_color, fill_color, + stroke_width, label_text); } if (new_paint_rects.size()) { @@ -986,13 +1045,10 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( if (fade_step_ > 0) { fade_step_--; for (size_t i = 0; i < paint_rects_.size(); ++i) { - DrawDebugRect(canvas, - &paint, - paint_rects_[i], + DrawDebugRect(canvas, &flags, paint_rects_[i], DebugColors::PaintRectBorderColor(fade_step_), DebugColors::PaintRectFillColor(fade_step_), - DebugColors::PaintRectBorderWidth(), - ""); + DebugColors::PaintRectBorderWidth(), ""); } } } diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h index 6102b0da115..9a97daea2d4 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.h +++ b/chromium/cc/layers/heads_up_display_layer_impl.h @@ -14,13 +14,12 @@ #include "base/time/time.h" #include "cc/cc_export.h" #include "cc/layers/layer_impl.h" +#include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/resources/memory_history.h" #include "cc/resources/resource_pool.h" #include "cc/trees/debug_rect_history.h" #include "third_party/skia/include/core/SkRefCnt.h" -class SkCanvas; -class SkPaint; class SkTypeface; struct SkRect; @@ -31,6 +30,10 @@ class ClientResourceProvider; namespace cc { class FrameRateCounter; class LayerTreeFrameSink; +class PaintCanvas; +class PaintFlags; + +enum class TextAlign { kLeft, kCenter, kRight }; class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { public: @@ -93,50 +96,49 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { void AsValueInto(base::trace_event::TracedValue* dict) const override; void UpdateHudContents(); - void DrawHudContents(SkCanvas* canvas); - - int MeasureText(SkPaint* paint, const std::string& text, int size) const; - void DrawText(SkCanvas* canvas, - SkPaint* paint, + void DrawHudContents(PaintCanvas* canvas); + void DrawText(PaintCanvas* canvas, + PaintFlags* flags, const std::string& text, - SkPaint::Align align, + TextAlign align, int size, int x, int y) const; - void DrawText(SkCanvas* canvas, - SkPaint* paint, + void DrawText(PaintCanvas* canvas, + PaintFlags* flags, const std::string& text, - SkPaint::Align align, + TextAlign align, int size, const SkPoint& pos) const; - void DrawGraphBackground(SkCanvas* canvas, - SkPaint* paint, + void DrawGraphBackground(PaintCanvas* canvas, + PaintFlags* flags, const SkRect& bounds) const; - void DrawGraphLines(SkCanvas* canvas, - SkPaint* paint, + void DrawGraphLines(PaintCanvas* canvas, + PaintFlags* flags, const SkRect& bounds, const Graph& graph) const; - SkRect DrawFPSDisplay(SkCanvas* canvas, + SkRect DrawFPSDisplay(PaintCanvas* canvas, const FrameRateCounter* fps_counter, int right, int top) const; - SkRect DrawMemoryDisplay(SkCanvas* canvas, + SkRect DrawMemoryDisplay(PaintCanvas* canvas, int top, int right, int width) const; - SkRect DrawGpuRasterizationStatus(SkCanvas* canvas, + SkRect DrawGpuRasterizationStatus(PaintCanvas* canvas, int right, int top, int width) const; - void DrawDebugRect(SkCanvas* canvas, - SkPaint* paint, + void DrawDebugRect(PaintCanvas* canvas, + PaintFlags* flags, const DebugRect& rect, SkColor stroke_color, SkColor fill_color, float stroke_width, const std::string& label_text) const; - void DrawDebugRects(SkCanvas* canvas, DebugRectHistory* debug_rect_history); + void DrawDebugRects(PaintCanvas* canvas, + DebugRectHistory* debug_rect_history); ResourcePool::InUsePoolResource in_flight_resource_; std::unique_ptr<ResourcePool> pool_; @@ -157,6 +159,9 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { base::TimeTicks time_of_last_graph_update_; + // color space for OOPR + const RasterColorSpace raster_color_space_; + DISALLOW_COPY_AND_ASSIGN(HeadsUpDisplayLayerImpl); }; diff --git a/chromium/cc/layers/heads_up_display_unittest.cc b/chromium/cc/layers/heads_up_display_unittest.cc index 840f82f8ef4..6ebce87e16e 100644 --- a/chromium/cc/layers/heads_up_display_unittest.cc +++ b/chromium/cc/layers/heads_up_display_unittest.cc @@ -82,5 +82,24 @@ class HudWithRootLayerChange : public HeadsUpDisplayTest { SINGLE_AND_MULTI_THREAD_TEST_F(HudWithRootLayerChange); +class HeadsUpDisplaySizeWithFPS : public LayerTreeTest { + public: + void InitializeSettings(LayerTreeSettings* settings) override { + settings->initial_debug_state.show_fps_counter = true; + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + ASSERT_TRUE(layer_tree_host()->hud_layer()); + EXPECT_EQ(gfx::Size(256, 256), layer_tree_host()->hud_layer()->bounds()); + EndTest(); + } + + void AfterTest() override {} +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(HeadsUpDisplaySizeWithFPS); + } // namespace } // namespace cc diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index dfc03bb5898..f976fa6e1aa 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -509,7 +509,7 @@ void Layer::SetMaskLayer(PictureLayer* mask_layer) { inputs_.mask_layer->RemoveFromParent(); DCHECK(!inputs_.mask_layer->parent()); inputs_.mask_layer->SetParent(this); - if (inputs_.filters.IsEmpty() && inputs_.background_filters.IsEmpty() && + if (inputs_.filters.IsEmpty() && inputs_.backdrop_filters.IsEmpty() && (!layer_tree_host_ || layer_tree_host_->GetSettings().enable_mask_tiling)) { inputs_.mask_layer->SetLayerMaskType( @@ -537,11 +537,11 @@ void Layer::SetFilters(const FilterOperations& filters) { SetNeedsCommit(); } -void Layer::SetBackgroundFilters(const FilterOperations& filters) { +void Layer::SetBackdropFilters(const FilterOperations& filters) { DCHECK(IsPropertyChangeAllowed()); - if (inputs_.background_filters == filters) + if (inputs_.backdrop_filters == filters) return; - inputs_.background_filters = filters; + inputs_.backdrop_filters = filters; // We will not set the mask type to MULTI_TEXTURE_MASK if the mask layer's // filters are removed, because we do not want to reraster if the filters are diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index 4e288f8cfb0..b90f4559bc0 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -278,9 +278,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // Set or get the list of filters that should be applied to the content this // layer and its subtree will be drawn into. The effect is clipped to only // apply directly behind this layer and its subtree. - void SetBackgroundFilters(const FilterOperations& filters); - const FilterOperations& background_filters() const { - return inputs_.background_filters; + void SetBackdropFilters(const FilterOperations& filters); + const FilterOperations& backdrop_filters() const { + return inputs_.backdrop_filters; } void SetBackdropFilterQuality(const float quality); @@ -900,7 +900,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { SkColor background_color; FilterOperations filters; - FilterOperations background_filters; + FilterOperations backdrop_filters; gfx::PointF filters_origin; float backdrop_filter_quality; diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index 3a4bf4536a8..3a1f4e9aadf 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -14,7 +14,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/math_util.h" #include "cc/base/simple_enclosed_region.h" #include "cc/benchmarks/micro_benchmark_impl.h" @@ -789,7 +789,7 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const { *state); if (debug_info_) - state->SetValue("debug_info", *debug_info_); + state->SetValue("debug_info", debug_info_); } size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; } diff --git a/chromium/cc/layers/layer_impl_test_properties.h b/chromium/cc/layers/layer_impl_test_properties.h index 038c420cac6..c931d45d95f 100644 --- a/chromium/cc/layers/layer_impl_test_properties.h +++ b/chromium/cc/layers/layer_impl_test_properties.h @@ -47,7 +47,7 @@ struct CC_EXPORT LayerImplTestProperties { int sorting_context_id; float opacity; FilterOperations filters; - FilterOperations background_filters; + FilterOperations backdrop_filters; float backdrop_filter_quality; gfx::PointF filters_origin; SkBlendMode blend_mode; diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc index 1b4dc11a35e..1f207f8e3bc 100644 --- a/chromium/cc/layers/layer_unittest.cc +++ b/chromium/cc/layers/layer_unittest.cc @@ -397,7 +397,7 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( - root->SetBackgroundFilters(arbitrary_filters)); + root->SetBackdropFilters(arbitrary_filters)); EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( root->PushPropertiesTo(root_impl.get()); child->PushPropertiesTo(child_impl.get()); diff --git a/chromium/cc/layers/nine_patch_generator.cc b/chromium/cc/layers/nine_patch_generator.cc index ac64a5049e1..7677f48bd11 100644 --- a/chromium/cc/layers/nine_patch_generator.cc +++ b/chromium/cc/layers/nine_patch_generator.cc @@ -360,7 +360,9 @@ void NinePatchGenerator::AppendQuads(LayerImpl* layer_impl, quad->SetNew(shared_quad_state, output_rect, visible_rect, needs_blending, resource, premultiplied_alpha, image_rect.origin(), image_rect.bottom_right(), SK_ColorTRANSPARENT, - vertex_opacity, flipped, nearest_neighbor_, false); + vertex_opacity, flipped, nearest_neighbor_, + /*secure_output_only=*/false, + ui::ProtectedVideoType::kClear); layer_impl->ValidateQuadResources(quad); } } diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc index 831dffcf63c..c7e055e541d 100644 --- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc @@ -158,11 +158,11 @@ void PaintedOverlayScrollbarLayerImpl::AppendTrackQuads( float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; viz::TextureDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>(); - quad->SetNew(shared_quad_state, scaled_track_quad_rect, - scaled_visible_track_quad_rect, needs_blending, - track_resource_id, premultipled_alpha, uv_top_left, - uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, - nearest_neighbor, false); + quad->SetNew( + shared_quad_state, scaled_track_quad_rect, scaled_visible_track_quad_rect, + needs_blending, track_resource_id, premultipled_alpha, uv_top_left, + uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor, + /*secure_output_only=*/false, ui::ProtectedVideoType::kClear); ValidateQuadResources(quad); } diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc index 912e2a0a322..09febcc0984 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc @@ -124,7 +124,8 @@ void PaintedScrollbarLayerImpl::AppendQuads( scaled_visible_thumb_quad_rect, needs_blending, thumb_resource_id, premultipled_alpha, uv_top_left, uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, - nearest_neighbor, false); + nearest_neighbor, /*secure_output_only=*/false, + ui::ProtectedVideoType::kClear); ValidateQuadResources(quad); } @@ -143,7 +144,8 @@ void PaintedScrollbarLayerImpl::AppendQuads( scaled_visible_track_quad_rect, needs_blending, track_resource_id, premultipled_alpha, uv_top_left, uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, - nearest_neighbor, false); + nearest_neighbor, /*secure_output_only=*/false, + ui::ProtectedVideoType::kClear); ValidateQuadResources(quad); } } diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index 94772c09ab4..5c4c58fc5da 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -15,7 +15,7 @@ #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" #include "base/time/time.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "build/build_config.h" #include "cc/base/math_util.h" #include "cc/benchmarks/micro_benchmark_impl.h" @@ -526,7 +526,8 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass, if (!has_draw_quad) { // Checkerboard. SkColor color = SafeOpaqueBackgroundColor(); - if (ShowDebugBorders(DebugBorderType::LAYER)) { + if (mask_type_ == Layer::LayerMaskType::NOT_MASK && + ShowDebugBorders(DebugBorderType::LAYER)) { // Fill the whole tile with the missing tile color. color = DebugColors::OOMTileBorderColor(); } @@ -1560,13 +1561,30 @@ void PictureLayerImpl::UpdateIdealScales() { float min_contents_scale = MinimumContentsScale(); DCHECK_GT(min_contents_scale, 0.f); - ideal_page_scale_ = IsAffectedByPageScale() - ? layer_tree_impl()->current_page_scale_factor() - : 1.f; ideal_device_scale_ = layer_tree_impl()->device_scale_factor(); + if (layer_tree_impl()->PageScaleLayer()) { + ideal_page_scale_ = IsAffectedByPageScale() + ? layer_tree_impl()->current_page_scale_factor() + : 1.f; + ideal_contents_scale_ = GetIdealContentsScale(); + } else { + // 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. + float external_page_scale_factor = + layer_tree_impl() ? layer_tree_impl()->external_page_scale_factor() + : 1.f; + DCHECK(!layer_tree_impl() || external_page_scale_factor == 1.f || + layer_tree_impl()->current_page_scale_factor() == 1.f); + ideal_page_scale_ = external_page_scale_factor; + ideal_contents_scale_ = + GetIdealContentsScale() * external_page_scale_factor; + } ideal_contents_scale_ = std::min(kMaxIdealContentsScale, - std::max(GetIdealContentsScale(), min_contents_scale)); + std::max(ideal_contents_scale_, min_contents_scale)); ideal_source_scale_ = ideal_contents_scale_ / ideal_page_scale_ / ideal_device_scale_; } diff --git a/chromium/cc/layers/recording_source_unittest.cc b/chromium/cc/layers/recording_source_unittest.cc index 15b5249fc10..dbdcaa17c49 100644 --- a/chromium/cc/layers/recording_source_unittest.cc +++ b/chromium/cc/layers/recording_source_unittest.cc @@ -16,10 +16,6 @@ namespace cc { namespace { -gfx::ColorSpace DefaultColorSpace() { - return gfx::ColorSpace::CreateSRGB(); -} - std::unique_ptr<FakeRecordingSource> CreateRecordingSource( const gfx::Rect& viewport) { gfx::Rect layer_rect(viewport.right(), viewport.bottom()); @@ -110,8 +106,7 @@ TEST(RecordingSourceTest, DiscardableImagesWithTransform) { std::vector<const DrawImage*> images; raster_source->GetDiscardableImagesInRect(gfx::Rect(130, 0, 128, 128), &images); - DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex); EXPECT_EQ(1u, images.size()); EXPECT_FLOAT_EQ(scale, image.scale().width()); EXPECT_FLOAT_EQ(scale, image.scale().height()); @@ -160,12 +155,8 @@ TEST(RecordingSourceTest, NoDiscardableImages) { PaintFlags simple_flags; simple_flags.setColor(SkColorSetARGB(255, 12, 23, 34)); - SkBitmap non_discardable_bitmap; - non_discardable_bitmap.allocN32Pixels(128, 128); - non_discardable_bitmap.setImmutable(); - sk_sp<SkImage> non_discardable_image = - SkImage::MakeFromBitmap(non_discardable_bitmap); - + auto non_discardable_image = + CreateNonDiscardablePaintImage(gfx::Size(128, 128)); recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 256, 256), simple_flags); recording_source->add_draw_rect_with_flags(gfx::Rect(128, 128, 512, 512), @@ -274,12 +265,8 @@ TEST(RecordingSourceTest, DiscardableImagesBaseNonDiscardable) { std::unique_ptr<FakeRecordingSource> recording_source = CreateRecordingSource(recorded_viewport); - - SkBitmap non_discardable_bitmap; - non_discardable_bitmap.allocN32Pixels(512, 512); - non_discardable_bitmap.setImmutable(); - sk_sp<SkImage> non_discardable_image = - SkImage::MakeFromBitmap(non_discardable_bitmap); + PaintImage non_discardable_image = + CreateNonDiscardablePaintImage(gfx::Size(512, 512)); PaintImage discardable_image[2][2]; discardable_image[0][0] = CreateDiscardablePaintImage(gfx::Size(128, 128)); diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc index 1461252b8ed..d4a0e72f590 100644 --- a/chromium/cc/layers/render_surface_impl.cc +++ b/chromium/cc/layers/render_surface_impl.cc @@ -149,8 +149,8 @@ gfx::Transform RenderSurfaceImpl::SurfaceScale() const { return surface_scale; } -const FilterOperations& RenderSurfaceImpl::BackgroundFilters() const { - return OwningEffectNode()->background_filters; +const FilterOperations& RenderSurfaceImpl::BackdropFilters() const { + return OwningEffectNode()->backdrop_filters; } bool RenderSurfaceImpl::TrilinearFiltering() const { @@ -374,7 +374,7 @@ std::unique_ptr<viz::RenderPass> RenderSurfaceImpl::CreateRenderPass() { pass->SetNew(id(), content_rect(), damage_rect, draw_properties_.screen_space_transform); pass->filters = Filters(); - pass->background_filters = BackgroundFilters(); + pass->backdrop_filters = BackdropFilters(); pass->generate_mipmap = TrilinearFiltering(); pass->cache_render_pass = ShouldCacheRenderSurface(); pass->has_damage_from_contributing_content = diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h index 8e7c143087f..6e648a4d8ff 100644 --- a/chromium/cc/layers/render_surface_impl.h +++ b/chromium/cc/layers/render_surface_impl.h @@ -149,7 +149,7 @@ class CC_EXPORT RenderSurfaceImpl { bool HasMaskingContributingSurface() const; const FilterOperations& Filters() const; - const FilterOperations& BackgroundFilters() const; + const FilterOperations& BackdropFilters() const; gfx::PointF FiltersOrigin() const; gfx::Transform SurfaceScale() const; diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc index 031d23cf451..4425f722798 100644 --- a/chromium/cc/layers/scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/scrollbar_layer_unittest.cc @@ -1342,7 +1342,7 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest { layer_tree_host_->SetViewportSizeAndScale( layer_tree_host_->device_viewport_size(), test_scale, - layer_tree_host_->local_surface_id_from_parent()); + layer_tree_host_->local_surface_id_allocation_from_parent()); scrollbar_layer->Update(); @@ -1407,7 +1407,7 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest { layer_tree_host_->SetViewportSizeAndScale( layer_tree_host_->device_viewport_size(), test_scale, - layer_tree_host_->local_surface_id_from_parent()); + layer_tree_host_->local_surface_id_allocation_from_parent()); scrollbar_layer->Update(); diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc index 89dca4bd5c4..7611dd03e9d 100644 --- a/chromium/cc/layers/surface_layer.cc +++ b/chromium/cc/layers/surface_layer.cc @@ -34,8 +34,8 @@ SurfaceLayer::~SurfaceLayer() { DCHECK(!layer_tree_host()); } -void SurfaceLayer::SetPrimarySurfaceId(const viz::SurfaceId& surface_id, - const DeadlinePolicy& deadline_policy) { +void SurfaceLayer::SetSurfaceId(const viz::SurfaceId& surface_id, + const DeadlinePolicy& deadline_policy) { if (surface_range_.end() == surface_id && deadline_policy.use_existing_deadline()) { return; @@ -46,7 +46,7 @@ void SurfaceLayer::SetPrimarySurfaceId(const viz::SurfaceId& surface_id, "LocalSurfaceId.Embed.Flow", TRACE_ID_GLOBAL(surface_id.local_surface_id().embed_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "SetPrimarySurfaceId", "surface_id", surface_id.ToString()); + "SetSurfaceId", "surface_id", surface_id.ToString()); if (layer_tree_host() && surface_range_.IsValid()) layer_tree_host()->RemoveSurfaceRange(surface_range_); @@ -67,7 +67,8 @@ void SurfaceLayer::SetPrimarySurfaceId(const viz::SurfaceId& surface_id, SetNeedsCommit(); } -void SurfaceLayer::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) { +void SurfaceLayer::SetOldestAcceptableFallback( + const viz::SurfaceId& surface_id) { // The fallback should never move backwards. DCHECK(!surface_range_.start() || !surface_range_.start()->IsNewerThan(surface_id)); @@ -78,7 +79,7 @@ void SurfaceLayer::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) { "LocalSurfaceId.Submission.Flow", TRACE_ID_GLOBAL(surface_id.local_surface_id().submission_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "SetFallbackSurfaceId", "surface_id", surface_id.ToString()); + "SetOldestAcceptableFallback", "surface_id", surface_id.ToString()); if (layer_tree_host() && surface_range_.IsValid()) layer_tree_host()->RemoveSurfaceRange(surface_range_); @@ -152,7 +153,7 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) { TRACE_EVENT0("cc", "SurfaceLayer::PushPropertiesTo"); SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer); layer_impl->SetRange(surface_range_, std::move(deadline_in_frames_)); - // Unless the client explicitly calls SetPrimarySurfaceId again after this + // Unless the client explicitly calls SetSurfaceId again after this // commit, don't block on |surface_range_| again. deadline_in_frames_ = 0u; layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_); diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h index 8a832fba879..61c78304062 100644 --- a/chromium/cc/layers/surface_layer.h +++ b/chromium/cc/layers/surface_layer.h @@ -27,9 +27,9 @@ class CC_EXPORT SurfaceLayer : public Layer { static scoped_refptr<SurfaceLayer> Create(); static scoped_refptr<SurfaceLayer> Create(UpdateSubmissionStateCB); - void SetPrimarySurfaceId(const viz::SurfaceId& surface_id, - const DeadlinePolicy& deadline_policy); - void SetFallbackSurfaceId(const viz::SurfaceId& surface_id); + void SetSurfaceId(const viz::SurfaceId& surface_id, + const DeadlinePolicy& deadline_policy); + void SetOldestAcceptableFallback(const viz::SurfaceId& surface_id); // When stretch_content_to_fill_bounds is true, the scale of the embedded // surface is ignored and the content will be stretched to fill the bounds. @@ -49,11 +49,9 @@ class CC_EXPORT SurfaceLayer : public Layer { void SetLayerTreeHost(LayerTreeHost* host) override; void PushPropertiesTo(LayerImpl* layer) override; - const viz::SurfaceId& primary_surface_id() const { - return surface_range_.end(); - } + const viz::SurfaceId& surface_id() const { return surface_range_.end(); } - const base::Optional<viz::SurfaceId>& fallback_surface_id() const { + const base::Optional<viz::SurfaceId>& oldest_acceptable_fallback() const { return surface_range_.start(); } diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc index ad3031ebcc1..23810a45400 100644 --- a/chromium/cc/layers/surface_layer_impl.cc +++ b/chromium/cc/layers/surface_layer_impl.cc @@ -6,7 +6,7 @@ #include <stdint.h> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/debug/debug_colors.h" #include "cc/layers/append_quads_data.h" #include "cc/trees/layer_tree_impl.h" @@ -49,8 +49,7 @@ void SurfaceLayerImpl::SetRange(const viz::SurfaceRange& surface_range, TRACE_ID_GLOBAL( surface_range.end().local_surface_id().embed_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "ImplSetPrimarySurfaceId", "surface_id", - surface_range.end().ToString()); + "ImplSetSurfaceId", "surface_id", surface_range.end().ToString()); } if (surface_range.start() && @@ -61,7 +60,7 @@ void SurfaceLayerImpl::SetRange(const viz::SurfaceRange& surface_range, TRACE_ID_GLOBAL( surface_range.start()->local_surface_id().submission_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "ImplSetFallbackSurfaceId", "surface_id", + "ImplSetOldestAcceptableFallback", "surface_id", surface_range.start()->ToString()); } @@ -180,7 +179,8 @@ viz::SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad( render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>(); surface_draw_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, surface_range, background_color(), - stretch_content_to_fill_bounds_); + stretch_content_to_fill_bounds_, + has_pointer_events_none_); return surface_draw_quad; } diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc index 57be59a6142..3faa62a9544 100644 --- a/chromium/cc/layers/surface_layer_unittest.cc +++ b/chromium/cc/layers/surface_layer_unittest.cc @@ -12,6 +12,7 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "cc/animation/animation_host.h" #include "cc/layers/solid_color_layer.h" #include "cc/layers/surface_layer.h" @@ -56,7 +57,7 @@ class SurfaceLayerTest : public testing::Test { layer_tree_host_ = FakeLayerTreeHost::Create( &fake_client_, &task_graph_runner_, animation_host_.get()); layer_tree_host_->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); host_impl_.CreatePendingTree(); } @@ -83,7 +84,7 @@ TEST_F(SurfaceLayerTest, UseExistingDeadlineForNewSurfaceLayer) { viz::SurfaceId primary_id( kArbitraryFrameSinkId, viz::LocalSurfaceId(1, base::UnguessableToken::Create())); - layer->SetPrimarySurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); EXPECT_EQ(0u, layer->deadline_in_frames()); } @@ -95,7 +96,7 @@ TEST_F(SurfaceLayerTest, UseInfiniteDeadlineForNewSurfaceLayer) { viz::SurfaceId primary_id( kArbitraryFrameSinkId, viz::LocalSurfaceId(1, base::UnguessableToken::Create())); - layer->SetPrimarySurfaceId(primary_id, DeadlinePolicy::UseInfiniteDeadline()); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseInfiniteDeadline()); EXPECT_EQ(std::numeric_limits<uint32_t>::max(), layer->deadline_in_frames()); } @@ -107,14 +108,13 @@ TEST_F(SurfaceLayerTest, ResetDeadlineOnInvalidSurfaceId) { viz::SurfaceId primary_id( kArbitraryFrameSinkId, viz::LocalSurfaceId(1, base::UnguessableToken::Create())); - layer->SetPrimarySurfaceId(primary_id, - DeadlinePolicy::UseSpecifiedDeadline(3u)); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(3u)); EXPECT_EQ(3u, layer->deadline_in_frames()); // Reset the surface layer to an invalid SurfaceId. Verify that the deadline // is reset. - layer->SetPrimarySurfaceId(viz::SurfaceId(), - DeadlinePolicy::UseSpecifiedDeadline(3u)); + layer->SetSurfaceId(viz::SurfaceId(), + DeadlinePolicy::UseSpecifiedDeadline(3u)); EXPECT_EQ(0u, layer->deadline_in_frames()); } @@ -126,12 +126,10 @@ TEST_F(SurfaceLayerTest, PushProperties) { viz::SurfaceId primary_id( kArbitraryFrameSinkId, viz::LocalSurfaceId(1, base::UnguessableToken::Create())); - layer->SetPrimarySurfaceId(primary_id, - DeadlinePolicy::UseSpecifiedDeadline(1u)); - layer->SetPrimarySurfaceId(primary_id, - DeadlinePolicy::UseSpecifiedDeadline(2u)); - layer->SetPrimarySurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); - layer->SetFallbackSurfaceId(primary_id); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(1u)); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(2u)); + layer->SetSurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); + layer->SetOldestAcceptableFallback(primary_id); layer->SetBackgroundColor(SK_ColorBLUE); layer->SetStretchContentToFillBounds(true); @@ -164,9 +162,8 @@ TEST_F(SurfaceLayerTest, PushProperties) { viz::SurfaceId fallback_id( kArbitraryFrameSinkId, viz::LocalSurfaceId(2, base::UnguessableToken::Create())); - layer->SetFallbackSurfaceId(fallback_id); - layer->SetPrimarySurfaceId(fallback_id, - DeadlinePolicy::UseExistingDeadline()); + layer->SetOldestAcceptableFallback(fallback_id); + layer->SetSurfaceId(fallback_id, DeadlinePolicy::UseExistingDeadline()); layer->SetBackgroundColor(SK_ColorGREEN); layer->SetStretchContentToFillBounds(false); @@ -201,17 +198,15 @@ TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) { // animation is done. scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(); layer1->SetLayerTreeHost(layer_tree_host_.get()); - layer1->SetPrimarySurfaceId(old_surface_id, - DeadlinePolicy::UseDefaultDeadline()); - layer1->SetFallbackSurfaceId(old_surface_id); + layer1->SetSurfaceId(old_surface_id, DeadlinePolicy::UseDefaultDeadline()); + layer1->SetOldestAcceptableFallback(old_surface_id); // This layer will eventually be switched be switched to show the new surface // id and will be retained when animation is done. scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(); layer2->SetLayerTreeHost(layer_tree_host_.get()); - layer2->SetPrimarySurfaceId(old_surface_id, - DeadlinePolicy::UseDefaultDeadline()); - layer2->SetFallbackSurfaceId(old_surface_id); + layer2->SetSurfaceId(old_surface_id, DeadlinePolicy::UseDefaultDeadline()); + layer2->SetOldestAcceptableFallback(old_surface_id); std::unique_ptr<SurfaceLayerImpl> layer_impl1 = SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer1->id()); @@ -231,9 +226,8 @@ TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) { viz::LocalSurfaceId(2, base::UnguessableToken::Create())); // Switch the new layer to use |new_surface_id|. - layer2->SetPrimarySurfaceId(new_surface_id, - DeadlinePolicy::UseDefaultDeadline()); - layer2->SetFallbackSurfaceId(new_surface_id); + layer2->SetSurfaceId(new_surface_id, DeadlinePolicy::UseDefaultDeadline()); + layer2->SetOldestAcceptableFallback(new_surface_id); SynchronizeTrees(); @@ -269,8 +263,8 @@ TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) { scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(); layer1->SetLayerTreeHost(layer_tree_host_.get()); - layer1->SetPrimarySurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); - layer1->SetFallbackSurfaceId(surface_id); + layer1->SetSurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); + layer1->SetOldestAcceptableFallback(surface_id); // Verify the surface id is in SurfaceLayerIds() and // needs_surface_ranges_sync() is true. @@ -287,8 +281,8 @@ TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) { // Create the second layer that is a clone of the first. scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(); layer2->SetLayerTreeHost(layer_tree_host_.get()); - layer2->SetPrimarySurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); - layer2->SetFallbackSurfaceId(surface_id); + layer2->SetSurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); + layer2->SetOldestAcceptableFallback(surface_id); // Verify that after creating the second layer with the same surface id that // needs_surface_ranges_sync() is still false. diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc index f1b6e748a16..9d2e07594a9 100644 --- a/chromium/cc/layers/texture_layer_impl.cc +++ b/chromium/cc/layers/texture_layer_impl.cc @@ -155,7 +155,8 @@ void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass, 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_, false); + nearest_neighbor_, /*secure_output_only=*/false, + ui::ProtectedVideoType::kClear); quad->set_resource_size_in_pixels(transferable_resource_.size); ValidateQuadResources(quad); } diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc index ef8c52d3697..de62de061e6 100644 --- a/chromium/cc/layers/texture_layer_unittest.cc +++ b/chromium/cc/layers/texture_layer_unittest.cc @@ -175,7 +175,7 @@ class TextureLayerTest : public testing::Test { &fake_client_, &task_graph_runner_, animation_host_.get()); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); layer_tree_host_->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); Mock::VerifyAndClearExpectations(layer_tree_host_.get()); } @@ -268,7 +268,7 @@ TEST_F(TextureLayerTest, ShutdownWithResource) { } host->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); host->SetVisible(true); host->SetRootLayer(layer); @@ -710,7 +710,7 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest { root_->AddChild(layer_); layer_tree_host()->SetRootLayer(root_); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); SetMailbox('1'); EXPECT_EQ(0, callback_count_); @@ -781,7 +781,7 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest { root_->AddChild(layer_); layer_tree_host()->SetRootLayer(root_); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); SetMailbox('1'); PostSetNeedsCommitToMainThread(); @@ -1312,7 +1312,7 @@ class TextureLayerWithResourceMainThreadDeleted : public LayerTreeTest { root_->AddChild(layer_); layer_tree_host()->SetRootLayer(root_); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); } void BeginTest() override { @@ -1382,7 +1382,7 @@ class TextureLayerWithResourceImplThreadDeleted : public LayerTreeTest { root_->AddChild(layer_); layer_tree_host()->SetRootLayer(root_); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); } void BeginTest() override { diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc index e34f189493d..c3a94fc6fbc 100644 --- a/chromium/cc/layers/ui_resource_layer_impl.cc +++ b/chromium/cc/layers/ui_resource_layer_impl.cc @@ -130,7 +130,7 @@ void UIResourceLayerImpl::AppendQuads(viz::RenderPass* render_pass, quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, needs_blending, resource, premultiplied_alpha, uv_top_left_, uv_bottom_right_, SK_ColorTRANSPARENT, vertex_opacity_, flipped, nearest_neighbor, - false); + /*secure_output_only=*/false, ui::ProtectedVideoType::kClear); ValidateQuadResources(quad); } diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc index c356a8f66a9..84c9913b451 100644 --- a/chromium/cc/layers/video_layer_impl.cc +++ b/chromium/cc/layers/video_layer_impl.cc @@ -122,6 +122,8 @@ void VideoLayerImpl::AppendQuads(viz::RenderPass* render_pass, DCHECK(frame_.get()); gfx::Transform transform = DrawTransform(); + // bounds() is in post-rotation space so quad rect in content space must be + // in pre-rotation space gfx::Size rotated_size = bounds(); switch (video_rotation_) { @@ -143,20 +145,19 @@ void VideoLayerImpl::AppendQuads(viz::RenderPass* render_pass, break; } + gfx::Rect quad_rect(rotated_size); Occlusion occlusion_in_video_space = draw_properties() .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform( transform); gfx::Rect visible_quad_rect = - occlusion_in_video_space.GetUnoccludedContentRect( - gfx::Rect(rotated_size)); + occlusion_in_video_space.GetUnoccludedContentRect(quad_rect); if (visible_quad_rect.IsEmpty()) return; - updater_->AppendQuads(render_pass, frame_, transform, rotated_size, - visible_quad_rect, clip_rect(), is_clipped(), - contents_opaque(), draw_opacity(), - GetSortingContextId(), visible_quad_rect); + updater_->AppendQuads( + render_pass, frame_, transform, quad_rect, visible_quad_rect, clip_rect(), + is_clipped(), contents_opaque(), draw_opacity(), GetSortingContextId()); } void VideoLayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) { diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc index f7f67de0341..f70e8e22646 100644 --- a/chromium/cc/layers/video_layer_impl_unittest.cc +++ b/chromium/cc/layers/video_layer_impl_unittest.cc @@ -394,8 +394,6 @@ TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) { ASSERT_TRUE(video_frame); video_frame->metadata()->SetBoolean(media::VideoFrameMetadata::ALLOW_OVERLAY, true); - video_frame->metadata()->SetBoolean( - media::VideoFrameMetadata::REQUIRE_OVERLAY, true); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -419,7 +417,6 @@ TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) { (yuv_draw_quad->ya_tex_size.height() + 1) / 2); EXPECT_EQ(yuv_draw_quad->uv_tex_size.width(), (yuv_draw_quad->ya_tex_size.width() + 1) / 2); - EXPECT_TRUE(yuv_draw_quad->require_overlay); } TEST(VideoLayerImplTest, NativeARGBFrameGeneratesTextureQuad) { diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc index 34be99f811b..3dfd15b8666 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc @@ -16,6 +16,7 @@ #include "cc/trees/layer_tree_frame_sink_client.h" #include "components/viz/client/hit_test_data_provider.h" #include "components/viz/client/local_surface_id_provider.h" +#include "components/viz/common/features.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/common/quads/compositor_frame.h" @@ -97,6 +98,10 @@ AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink( "GraphicsPipeline.%s.SubmitCompositorFrameAfterBeginFrame", params->client_name)), weak_factory_(this) { + // We should not create hit test data provider if we want to use cc layer tree + // to generated data. + if (features::IsVizHitTestingSurfaceLayerEnabled()) + DCHECK(!params->hit_test_data_provider); DETACH_FROM_THREAD(thread_checker_); } @@ -161,7 +166,8 @@ void AsyncLayerTreeFrameSink::SetLocalSurfaceId( } void AsyncLayerTreeFrameSink::SubmitCompositorFrame( - viz::CompositorFrame frame) { + viz::CompositorFrame frame, + bool show_hit_test_borders) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(compositor_frame_sink_ptr_); DCHECK(frame.metadata.begin_frame_ack.has_damage); @@ -180,8 +186,11 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame( } if (!enable_surface_synchronization_) { - local_surface_id_ = - local_surface_id_provider_->GetLocalSurfaceIdForFrame(frame); + const viz::LocalSurfaceIdAllocation& local_surface_id_allocation = + local_surface_id_provider_->GetLocalSurfaceIdAllocationForFrame(frame); + local_surface_id_ = local_surface_id_allocation.local_surface_id(); + frame.metadata.local_surface_id_allocation_time = + local_surface_id_allocation.allocation_time(); } else { if (local_surface_id_ == last_submitted_local_surface_id_) { DCHECK_EQ(last_submitted_device_scale_factor_, @@ -205,6 +214,9 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame( else hit_test_region_list = client_->BuildHitTestData(); + if (show_hit_test_borders && hit_test_region_list) + hit_test_region_list->flags |= viz::HitTestRegionFlags::kHitTestDebug; + if (last_submitted_local_surface_id_ != local_surface_id_) { last_submitted_local_surface_id_ = local_surface_id_; last_submitted_device_scale_factor_ = frame.device_scale_factor(); @@ -260,6 +272,11 @@ void AsyncLayerTreeFrameSink::DidDeleteSharedBitmap( compositor_frame_sink_ptr_->DidDeleteSharedBitmap(id); } +void AsyncLayerTreeFrameSink::ForceAllocateNewId() { + DCHECK(!enable_surface_synchronization_); + local_surface_id_provider_->ForceAllocateNewId(); +} + void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck( const std::vector<viz::ReturnedResource>& resources) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -267,14 +284,13 @@ void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck( client_->DidReceiveCompositorFrameAck(); } -void AsyncLayerTreeFrameSink::DidPresentCompositorFrame( - uint32_t presentation_token, - const gfx::PresentationFeedback& feedback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - client_->DidPresentCompositorFrame(presentation_token, feedback); -} +void AsyncLayerTreeFrameSink::OnBeginFrame( + const viz::BeginFrameArgs& args, + const base::flat_map<uint32_t, gfx::PresentationFeedback>& feedbacks) { + for (const auto& pair : feedbacks) { + client_->DidPresentCompositorFrame(pair.first, pair.second); + } -void AsyncLayerTreeFrameSink::OnBeginFrame(const viz::BeginFrameArgs& args) { DCHECK_LE(pipeline_reporting_frame_times_.size(), 25u); if (args.trace_id != -1) { base::TimeTicks current_time = base::TimeTicks::Now(); diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h index 71be58d39f3..f3f3be12461 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h @@ -117,20 +117,21 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink bool BindToClient(LayerTreeFrameSinkClient* client) override; void DetachFromClient() override; void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) override; - void SubmitCompositorFrame(viz::CompositorFrame frame) override; + void SubmitCompositorFrame(viz::CompositorFrame frame, + bool show_hit_test_borders) override; void DidNotProduceFrame(const viz::BeginFrameAck& ack) override; void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, const viz::SharedBitmapId& id) override; void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override; + void ForceAllocateNewId() override; private: // mojom::CompositorFrameSinkClient implementation: void DidReceiveCompositorFrameAck( const std::vector<viz::ReturnedResource>& resources) override; - void DidPresentCompositorFrame( - uint32_t presentation_token, - const gfx::PresentationFeedback& feedback) override; - void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args) override; + void OnBeginFrame(const viz::BeginFrameArgs& begin_frame_args, + const base::flat_map<uint32_t, gfx::PresentationFeedback>& + feedbacks) override; void OnBeginFramePausedChanged(bool paused) override; void ReclaimResources( const std::vector<viz::ReturnedResource>& resources) override; diff --git a/chromium/cc/paint/BUILD.gn b/chromium/cc/paint/BUILD.gn index 6ea4596b91b..21c6b8b7b5d 100644 --- a/chromium/cc/paint/BUILD.gn +++ b/chromium/cc/paint/BUILD.gn @@ -31,14 +31,14 @@ cc_component("paint") { "image_provider.h", "image_transfer_cache_entry.cc", "image_transfer_cache_entry.h", + "paint_cache.cc", + "paint_cache.h", "paint_canvas.h", "paint_export.h", "paint_filter.cc", "paint_filter.h", "paint_flags.cc", "paint_flags.h", - "paint_font.cc", - "paint_font.h", "paint_image.cc", "paint_image.h", "paint_image_builder.cc", @@ -59,12 +59,6 @@ cc_component("paint") { "paint_recorder.h", "paint_shader.cc", "paint_shader.h", - "paint_text_blob.cc", - "paint_text_blob.h", - "paint_text_blob_builder.cc", - "paint_text_blob_builder.h", - "path_transfer_cache_entry.cc", - "path_transfer_cache_entry.h", "raw_memory_transfer_cache_entry.cc", "raw_memory_transfer_cache_entry.h", "record_paint_canvas.cc", @@ -79,6 +73,8 @@ cc_component("paint") { "skia_paint_canvas.h", "skia_paint_image_generator.cc", "skia_paint_image_generator.h", + "skottie_wrapper.cc", + "skottie_wrapper.h", "solid_color_analyzer.cc", "solid_color_analyzer.h", "transfer_cache_deserialize_helper.h", @@ -124,19 +120,6 @@ fuzzer_test("paint_op_buffer_fuzzer") { ] } -fuzzer_test("paint_op_buffer_eq_fuzzer") { - sources = [ - "paint_op_buffer_eq_fuzzer.cc", - ] - - libfuzzer_options = [ "max_len=4096" ] - - deps = [ - "//cc:test_support", - "//cc/paint", - ] -} - fuzzer_test("transfer_cache_fuzzer") { sources = [ "transfer_cache_fuzzer.cc", diff --git a/chromium/cc/paint/DEPS b/chromium/cc/paint/DEPS index 78b223c0245..6d60ad8e8d6 100644 --- a/chromium/cc/paint/DEPS +++ b/chromium/cc/paint/DEPS @@ -9,4 +9,7 @@ specific_include_rules = { "oop_pixeltest.cc": [ "+gpu/command_buffer", ], + "skottie_wrapper.h": [ + "+third_party/skia", + ], } diff --git a/chromium/cc/paint/decoded_draw_image.h b/chromium/cc/paint/decoded_draw_image.h index 3079fc48b9c..63bc1ca4e25 100644 --- a/chromium/cc/paint/decoded_draw_image.h +++ b/chromium/cc/paint/decoded_draw_image.h @@ -17,6 +17,11 @@ namespace cc { +// A DecodedDrawImage is a finalized (decoded, scaled, colorspace converted, +// possibly uploaded) version of a DrawImage. When this image is going to +// be serialized, it uses the transfer cache entry id (see the function +// PaintOpWriter::Write(DrawImage&) constructor. When this image is going +// to be rastered directly, it uses the SkImage constructor. class CC_PAINT_EXPORT DecodedDrawImage { public: DecodedDrawImage(sk_sp<const SkImage> image, diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc index 1c53bb9b523..c9462f1595c 100644 --- a/chromium/cc/paint/discardable_image_map.cc +++ b/chromium/cc/paint/discardable_image_map.cc @@ -349,7 +349,7 @@ class DiscardableImageGenerator { const gfx::Rect& image_rect, const SkMatrix& matrix, SkFilterQuality filter_quality) { - if (!paint_image.IsLazyGenerated()) + if (paint_image.IsTextureBacked()) return; SkIRect src_irect; @@ -452,7 +452,7 @@ DiscardableImageMap::TakeDecodingModeMap() { void DiscardableImageMap::GetDiscardableImagesInRect( const gfx::Rect& rect, std::vector<const DrawImage*>* images) const { - *images = images_rtree_.SearchRefs(rect); + images_rtree_.SearchRefs(rect, images); } const DiscardableImageMap::Rects& DiscardableImageMap::GetRectsForImage( diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc index 72d608b2e35..32ec754bbe1 100644 --- a/chromium/cc/paint/discardable_image_map_unittest.cc +++ b/chromium/cc/paint/discardable_image_map_unittest.cc @@ -55,17 +55,16 @@ class DiscardableImageMapTest : public testing::Test { const DiscardableImageMap& image_map, const gfx::Rect& rect) { std::vector<const DrawImage*> draw_image_ptrs; - // Choose a not-SRGB-and-not-invalid target color space to verify that it - // is passed correctly to the resulting DrawImages. - gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); image_map.GetDiscardableImagesInRect(rect, &draw_image_ptrs); std::vector<DrawImage> draw_images; for (const auto* image : draw_image_ptrs) - draw_images.push_back(DrawImage( - *image, 1.f, PaintImage::kDefaultFrameIndex, target_color_space)); + draw_images.push_back( + DrawImage(*image, 1.f, PaintImage::kDefaultFrameIndex)); std::vector<PositionScaleDrawImage> position_draw_images; - for (DrawImage& image : image_map.images_rtree_.Search(rect)) { + std::vector<DrawImage> results; + image_map.images_rtree_.Search(rect, &results); + for (DrawImage& image : results) { auto image_id = image.paint_image().stable_id(); position_draw_images.push_back(PositionScaleDrawImage( image.paint_image(), @@ -77,7 +76,6 @@ class DiscardableImageMapTest : public testing::Test { for (size_t i = 0; i < draw_images.size(); ++i) { EXPECT_TRUE(draw_images[i].paint_image() == position_draw_images[i].image); - EXPECT_EQ(draw_images[i].target_color_space(), target_color_space); } return position_draw_images; } diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc index cc8db474af3..cacbe80e5a5 100644 --- a/chromium/cc/paint/display_item_list.cc +++ b/chromium/cc/paint/display_item_list.cc @@ -9,7 +9,7 @@ #include <string> #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/math_util.h" #include "cc/debug/picture_debug_util.h" #include "cc/paint/solid_color_analyzer.h" @@ -51,7 +51,8 @@ void DisplayItemList::Raster(SkCanvas* canvas, if (!GetCanvasClipBounds(canvas, &canvas_playback_rect)) return; - std::vector<size_t> offsets = rtree_.Search(canvas_playback_rect); + std::vector<size_t> offsets; + rtree_.Search(canvas_playback_rect, &offsets); paint_op_buffer_.Playback(canvas, PlaybackParams(image_provider), &offsets); } @@ -196,7 +197,7 @@ bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect, std::vector<size_t>* offsets_to_use = nullptr; std::vector<size_t> offsets; if (!rect.Contains(rtree_.GetBounds())) { - offsets = rtree_.Search(rect); + rtree_.Search(rect, &offsets); offsets_to_use = &offsets; } diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc index 5bcca13606d..0abe50d535c 100644 --- a/chromium/cc/paint/display_item_list_unittest.cc +++ b/chromium/cc/paint/display_item_list_unittest.cc @@ -8,7 +8,7 @@ #include <vector> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/paint/filter_operation.h" #include "cc/paint/filter_operations.h" diff --git a/chromium/cc/paint/draw_image.cc b/chromium/cc/paint/draw_image.cc index a1a78af3b6c..984ccd5c87d 100644 --- a/chromium/cc/paint/draw_image.cc +++ b/chromium/cc/paint/draw_image.cc @@ -32,28 +32,24 @@ DrawImage::DrawImage(PaintImage image, const SkIRect& src_rect, SkFilterQuality filter_quality, const SkMatrix& matrix, - base::Optional<size_t> frame_index, - const base::Optional<gfx::ColorSpace>& color_space) + base::Optional<size_t> frame_index) : paint_image_(std::move(image)), src_rect_(src_rect), filter_quality_(filter_quality), - frame_index_(frame_index), - target_color_space_(color_space) { + frame_index_(frame_index) { matrix_is_decomposable_ = ExtractScale(matrix, &scale_); } DrawImage::DrawImage(const DrawImage& other, float scale_adjustment, - size_t frame_index, - const gfx::ColorSpace& color_space) + size_t frame_index) : paint_image_(other.paint_image_), src_rect_(other.src_rect_), filter_quality_(other.filter_quality_), scale_(SkSize::Make(other.scale_.width() * scale_adjustment, other.scale_.height() * scale_adjustment)), matrix_is_decomposable_(other.matrix_is_decomposable_), - frame_index_(frame_index), - target_color_space_(color_space) {} + frame_index_(frame_index) {} DrawImage::DrawImage(const DrawImage& other) = default; DrawImage::DrawImage(DrawImage&& other) = default; @@ -65,8 +61,7 @@ DrawImage& DrawImage::operator=(const DrawImage& other) = default; bool DrawImage::operator==(const DrawImage& other) const { return paint_image_ == other.paint_image_ && src_rect_ == other.src_rect_ && filter_quality_ == other.filter_quality_ && scale_ == other.scale_ && - matrix_is_decomposable_ == other.matrix_is_decomposable_ && - target_color_space_ == other.target_color_space_; + matrix_is_decomposable_ == other.matrix_is_decomposable_; } } // namespace cc diff --git a/chromium/cc/paint/draw_image.h b/chromium/cc/paint/draw_image.h index 81c45d1cfd2..615b25eac11 100644 --- a/chromium/cc/paint/draw_image.h +++ b/chromium/cc/paint/draw_image.h @@ -13,11 +13,14 @@ #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRefCnt.h" -#include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size_f.h" namespace cc { +// A DrawImage is a logical snapshot in time and space of a PaintImage. It +// includes decisions about scaling, animation frame, etc. +// It has not been decoded yet. DrawImage turns into DecodedDrawImage via +// ImageDecodeCache::GetDecodedImageForDraw during playback. class CC_PAINT_EXPORT DrawImage { public: DrawImage(); @@ -25,14 +28,9 @@ class CC_PAINT_EXPORT DrawImage { const SkIRect& src_rect, SkFilterQuality filter_quality, const SkMatrix& matrix, - base::Optional<size_t> frame_index = base::nullopt, - const base::Optional<gfx::ColorSpace>& color_space = base::nullopt); - // Constructs a DrawImage from |other| by adjusting its scale and setting a - // new color_space. - DrawImage(const DrawImage& other, - float scale_adjustment, - size_t frame_index, - const gfx::ColorSpace& color_space); + base::Optional<size_t> frame_index = base::nullopt); + // Constructs a DrawImage from |other| by adjusting its scale and frame. + DrawImage(const DrawImage& other, float scale_adjustment, size_t frame_index); DrawImage(const DrawImage& other); DrawImage(DrawImage&& other); ~DrawImage(); @@ -47,10 +45,6 @@ class CC_PAINT_EXPORT DrawImage { const SkIRect& src_rect() const { return src_rect_; } SkFilterQuality filter_quality() const { return filter_quality_; } bool matrix_is_decomposable() const { return matrix_is_decomposable_; } - const gfx::ColorSpace& target_color_space() const { - DCHECK(target_color_space_.has_value()); - return *target_color_space_; - } PaintImage::FrameKey frame_key() const { return paint_image_.GetKeyForFrame(frame_index()); } @@ -66,7 +60,6 @@ class CC_PAINT_EXPORT DrawImage { SkSize scale_; bool matrix_is_decomposable_; base::Optional<size_t> frame_index_; - base::Optional<gfx::ColorSpace> target_color_space_; }; } // namespace cc diff --git a/chromium/cc/paint/filter_operation.cc b/chromium/cc/paint/filter_operation.cc index 221dd572fb7..3357afb235c 100644 --- a/chromium/cc/paint/filter_operation.cc +++ b/chromium/cc/paint/filter_operation.cc @@ -9,7 +9,7 @@ #include "cc/paint/filter_operation.h" #include "base/numerics/ranges.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/base/math_util.h" #include "ui/gfx/animation/tween.h" diff --git a/chromium/cc/paint/filter_operations.cc b/chromium/cc/paint/filter_operations.cc index cc2dcc5f7e6..a7e7312c381 100644 --- a/chromium/cc/paint/filter_operations.cc +++ b/chromium/cc/paint/filter_operations.cc @@ -9,7 +9,7 @@ #include <cmath> #include <numeric> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/paint/filter_operation.h" #include "ui/gfx/geometry/rect.h" diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc index c902b642b66..dedc9add23c 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.cc +++ b/chromium/cc/paint/image_transfer_cache_entry.cc @@ -104,7 +104,7 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const { // We don't need to populate the SerializeOptions here since the writer is // only used for serializing primitives. PaintOp::SerializeOptions options(nullptr, nullptr, nullptr, nullptr, nullptr, - false, false, 0, 0, SkMatrix::I()); + nullptr, false, false, 0, 0, SkMatrix::I()); PaintOpWriter writer(data.data(), data.size(), options); writer.Write(pixmap_->colorType()); writer.Write(pixmap_->width()); @@ -144,7 +144,7 @@ bool ServiceImageTransferCacheEntry::Deserialize( // We don't need to populate the DeSerializeOptions here since the reader is // only used for de-serializing primitives. - PaintOp::DeserializeOptions options(nullptr, nullptr); + PaintOp::DeserializeOptions options(nullptr, nullptr, nullptr); PaintOpReader reader(data.data(), data.size(), options); SkColorType color_type; reader.Read(&color_type); diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc index d79fa1c341c..f86a674a381 100644 --- a/chromium/cc/paint/oop_pixeltest.cc +++ b/chromium/cc/paint/oop_pixeltest.cc @@ -14,7 +14,6 @@ #include "cc/paint/display_item_list.h" #include "cc/paint/paint_filter.h" #include "cc/paint/paint_image_builder.h" -#include "cc/paint/paint_text_blob_builder.h" #include "cc/raster/playback_image_provider.h" #include "cc/raster/raster_source.h" #include "cc/test/pixel_test_utils.h" @@ -22,9 +21,12 @@ #include "cc/tiles/gpu_image_decode_cache.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/command_buffer/client/raster_implementation.h" #include "gpu/command_buffer/client/raster_implementation_gles.h" +#include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/client/shared_memory_limits.h" #include "gpu/command_buffer/common/context_creation_attribs.h" +#include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/gr_shader_cache.h" #include "gpu/config/gpu_switches.h" #include "gpu/ipc/gl_in_process_context.h" @@ -74,22 +76,11 @@ class OopPixelTest : public testing::Test, void SetUp() override { InitializeOOPContext(); - const int raster_max_texture_size = - raster_context_provider_->ContextCapabilities().max_texture_size; - gles2_context_provider_ = base::MakeRefCounted<TestInProcessContextProvider>( /*enable_oop_rasterization=*/false, /*support_locking=*/true); gpu::ContextResult result = gles2_context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); - const int gles2_max_texture_size = - raster_context_provider_->ContextCapabilities().max_texture_size; - gpu_image_cache_.reset(new GpuImageDecodeCache( - gles2_context_provider_.get(), false, kRGBA_8888_SkColorType, - kWorkingSetSize, gles2_max_texture_size, - PaintImage::kDefaultGeneratorClientId)); - - ASSERT_EQ(raster_max_texture_size, gles2_max_texture_size); } // gpu::raster::GrShaderCache::Client implementation. @@ -106,12 +97,24 @@ class OopPixelTest : public testing::Test, &gr_shader_cache_, &activity_flags_); gpu::ContextResult result = raster_context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); + } + + void CreateGpuImageCache(const gfx::ColorSpace& color_space) { + const int gles2_max_texture_size = + raster_context_provider_->ContextCapabilities().max_texture_size; + gpu_image_cache_.reset(new GpuImageDecodeCache( + gles2_context_provider_.get(), false, kRGBA_8888_SkColorType, + kWorkingSetSize, gles2_max_texture_size, + PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace())); + } + + void CreateOopImageCache(const gfx::ColorSpace& color_space) { const int raster_max_texture_size = raster_context_provider_->ContextCapabilities().max_texture_size; oop_image_cache_.reset(new GpuImageDecodeCache( raster_context_provider_.get(), true, kRGBA_8888_SkColorType, kWorkingSetSize, raster_max_texture_size, - PaintImage::kDefaultGeneratorClientId)); + PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace())); } class RasterOptions { @@ -140,6 +143,7 @@ class OopPixelTest : public testing::Test, SkColor preclear_color; ImageDecodeCache* image_cache = nullptr; std::vector<scoped_refptr<DisplayItemList>> additional_lists; + PaintShader* shader_with_animated_images = nullptr; }; SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list, @@ -150,36 +154,33 @@ class OopPixelTest : public testing::Test, SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list, const RasterOptions& options) { + CreateOopImageCache(options.color_space); + GURL url("https://example.com/foo"); TestInProcessContextProvider::ScopedRasterContextLock lock( raster_context_provider_.get(), url.possibly_invalid_spec().c_str()); PlaybackImageProvider image_provider(oop_image_cache_.get(), - options.color_space, PlaybackImageProvider::Settings()); gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL(); int width = options.resource_size.width(); int height = options.resource_size.height(); - // Create and allocate a texture on the raster interface. - GLuint raster_texture_id; - + // Create and allocate a shared image on the raster interface. auto* raster_implementation = raster_context_provider_->RasterInterface(); - raster_texture_id = raster_implementation->CreateTexture( - false, gfx::BufferUsage::GPU_READ, viz::ResourceFormat::RGBA_8888); - raster_implementation->TexStorage2D(raster_texture_id, width, height); - raster_implementation->TexParameteri(raster_texture_id, - GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - EXPECT_EQ(raster_implementation->GetError(), - static_cast<unsigned>(GL_NO_ERROR)); + auto* sii = raster_context_provider_->SharedImageInterface(); + uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER | + gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; + gpu::Mailbox mailbox = sii->CreateSharedImage( + viz::ResourceFormat::RGBA_8888, gfx::Size(width, height), + options.color_space, flags); + EXPECT_TRUE(mailbox.Verify()); + raster_implementation->WaitSyncTokenCHROMIUM( + sii->GenUnverifiedSyncToken().GetConstData()); RasterColorSpace color_space(options.color_space, ++color_space_id_); - gpu::Mailbox mailbox; - raster_implementation->ProduceTextureDirect(raster_texture_id, - mailbox.name); if (options.preclear) { raster_implementation->BeginRasterCHROMIUM( options.preclear_color, options.msaa_sample_count, @@ -224,8 +225,9 @@ class OopPixelTest : public testing::Test, gl->DeleteTextures(1, &gl_texture_id); gl->DeleteFramebuffers(1, &fbo_id); - gl->OrderingBarrierCHROMIUM(); - raster_implementation->DeleteTextures(1, &raster_texture_id); + gpu::SyncToken sync_token; + gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + sii->DestroySharedImage(sync_token, mailbox); // Swizzle rgba->bgra if needed. std::vector<SkPMColor> colors; @@ -258,6 +260,8 @@ class OopPixelTest : public testing::Test, SkBitmap RasterExpectedBitmap( scoped_refptr<DisplayItemList> display_item_list, const RasterOptions& options) { + CreateGpuImageCache(options.color_space); + TestInProcessContextProvider::ScopedRasterContextLock lock( gles2_context_provider_.get()); gles2_context_provider_->GrContext()->resetContext(); @@ -275,8 +279,10 @@ class OopPixelTest : public testing::Test, layer_rect); recording.SetRequiresClear(options.requires_clear); + if (options.shader_with_animated_images) + options.shader_with_animated_images->set_has_animated_images(true); + PlaybackImageProvider image_provider(gpu_image_cache_.get(), - options.color_space, PlaybackImageProvider::Settings()); auto raster_source = recording.CreateRasterSource(); @@ -605,9 +611,6 @@ TEST_P(OopImagePixelTest, DrawRecordShaderWithImageScaled) { auto paint_record_shader = PaintShader::MakePaintRecord( paint_record, gfx::RectToSkRect(rect), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, nullptr); - // Set the shader has animated images so gpu also goes through cc's image - // upload stack, instead of using skia. - paint_record_shader->set_has_animated_images(true); auto display_item_list = base::MakeRefCounted<DisplayItemList>(); display_item_list->StartPaint(); @@ -620,7 +623,11 @@ TEST_P(OopImagePixelTest, DrawRecordShaderWithImageScaled) { display_item_list->Finalize(); auto actual = Raster(display_item_list, rect.size()); - auto expected = RasterExpectedBitmap(display_item_list, rect.size()); + // Set the shader has animated images so gpu also goes through cc's image + // upload stack, instead of using skia. + RasterOptions expected_options(rect.size()); + expected_options.shader_with_animated_images = paint_record_shader.get(); + auto expected = RasterExpectedBitmap(display_item_list, expected_options); ExpectEquals(actual, expected); } @@ -1202,8 +1209,11 @@ TEST_F(OopPixelTest, ClearingTransparentInternalTile) { options.preclear = true; options.preclear_color = SK_ColorRED; - // Make a non-empty but noop display list to avoid early outs. - auto display_item_list = MakeNoopDisplayItemList(); + // 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 + // result in no items being generated, in which case a clear should still + // happen. See crbug.com/901897. + auto display_item_list = base::MakeRefCounted<DisplayItemList>(); auto oop_result = Raster(display_item_list, options); auto gpu_result = RasterExpectedBitmap(display_item_list, options); @@ -1386,33 +1396,31 @@ TEST_F(OopPixelTest, DrawRectColorSpace) { ExpectEquals(actual, expected); } -scoped_refptr<PaintTextBlob> BuildTextBlob( +sk_sp<SkTextBlob> BuildTextBlob( sk_sp<SkTypeface> typeface = SkTypeface::MakeDefault(), bool use_lcd_text = false) { if (!typeface) { typeface = SkTypeface::MakeFromName("monospace", SkFontStyle()); } - PaintFont font; - font.SetTypeface(typeface); - font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding); - font.SetHinting(SkPaint::kNormal_Hinting); - font.SetTextSize(1u); + SkFont font; + font.setTypeface(typeface); + font.setHinting(SkFontHinting::kNormal); + font.setSize(1u); if (use_lcd_text) { - font.SetAntiAlias(true); - font.SetSubpixelText(true); - font.SetLcdRenderText(true); + font.setSubpixel(true); + font.setEdging(SkFont::Edging::kSubpixelAntiAlias); } - PaintTextBlobBuilder builder; + SkTextBlobBuilder builder; SkRect bounds = SkRect::MakeWH(100, 100); const int glyphCount = 10; - const auto& runBuffer = builder.AllocRunPosH(font, glyphCount, 0, &bounds); + const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds); for (int i = 0; i < glyphCount; i++) { runBuffer.glyphs[i] = static_cast<SkGlyphID>(i); runBuffer.pos[i] = SkIntToScalar(i); } - return builder.TakeTextBlob(); + return builder.make(); } TEST_F(OopPixelTest, DrawTextBlob) { @@ -1439,87 +1447,87 @@ TEST_F(OopPixelTest, DrawTextBlob) { class OopRecordShaderPixelTest : public OopPixelTest, public ::testing::WithParamInterface<bool> { - public: - bool UseLcdText() const { return GetParam(); } - void RunTest() { - ScopedEnableLCDText enable_lcd; - - RasterOptions options; - options.resource_size = gfx::Size(100, 100); - options.content_size = options.resource_size; - options.full_raster_rect = gfx::Rect(options.content_size); - options.playback_rect = options.full_raster_rect; - options.color_space = gfx::ColorSpace::CreateSRGB(); - options.use_lcd_text = UseLcdText(); - - auto paint_record = sk_make_sp<PaintOpBuffer>(); - PaintFlags flags; - flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); - paint_record->push<DrawTextBlobOp>( - BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags); - auto paint_record_shader = PaintShader::MakePaintRecord( + public: + bool UseLcdText() const { return GetParam(); } + void RunTest() { + ScopedEnableLCDText enable_lcd; + + RasterOptions options; + options.resource_size = gfx::Size(100, 100); + options.content_size = options.resource_size; + options.full_raster_rect = gfx::Rect(options.content_size); + options.playback_rect = options.full_raster_rect; + options.color_space = gfx::ColorSpace::CreateSRGB(); + options.use_lcd_text = UseLcdText(); + + auto paint_record = sk_make_sp<PaintOpBuffer>(); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(SK_ColorGREEN); + paint_record->push<DrawTextBlobOp>( + BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags); + auto paint_record_shader = PaintShader::MakePaintRecord( paint_record, SkRect::MakeWH(25, 25), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, nullptr); - auto display_item_list = base::MakeRefCounted<DisplayItemList>(); - display_item_list->StartPaint(); - display_item_list->push<ScaleOp>(2.f, 2.f); - PaintFlags shader_flags; - shader_flags.setShader(paint_record_shader); - display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags); - display_item_list->EndPaintOfUnpaired(options.full_raster_rect); - display_item_list->Finalize(); - - auto actual = Raster(display_item_list, options); - auto expected = RasterExpectedBitmap(display_item_list, options); - ExpectEquals(actual, expected); - } + auto display_item_list = base::MakeRefCounted<DisplayItemList>(); + display_item_list->StartPaint(); + display_item_list->push<ScaleOp>(2.f, 2.f); + PaintFlags shader_flags; + shader_flags.setShader(paint_record_shader); + display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags); + display_item_list->EndPaintOfUnpaired(options.full_raster_rect); + display_item_list->Finalize(); + + auto actual = Raster(display_item_list, options); + auto expected = RasterExpectedBitmap(display_item_list, options); + ExpectEquals(actual, expected); + } }; - + TEST_P(OopRecordShaderPixelTest, ShaderWithTextScaled) { RunTest(); } - + class OopRecordFilterPixelTest : public OopPixelTest, public ::testing::WithParamInterface<bool> { - public: - bool UseLcdText() const { return GetParam(); } - void RunTest() { - ScopedEnableLCDText enable_lcd; - - RasterOptions options; - options.resource_size = gfx::Size(100, 100); - options.content_size = options.resource_size; - options.full_raster_rect = gfx::Rect(options.content_size); - options.playback_rect = options.full_raster_rect; - options.color_space = gfx::ColorSpace::CreateSRGB(); - options.use_lcd_text = UseLcdText(); - - auto paint_record = sk_make_sp<PaintOpBuffer>(); - PaintFlags flags; - flags.setStyle(PaintFlags::kFill_Style); - flags.setColor(SK_ColorGREEN); - paint_record->push<DrawTextBlobOp>( - BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags); - auto paint_record_filter = + public: + bool UseLcdText() const { return GetParam(); } + void RunTest() { + ScopedEnableLCDText enable_lcd; + + RasterOptions options; + options.resource_size = gfx::Size(100, 100); + options.content_size = options.resource_size; + options.full_raster_rect = gfx::Rect(options.content_size); + options.playback_rect = options.full_raster_rect; + options.color_space = gfx::ColorSpace::CreateSRGB(); + options.use_lcd_text = UseLcdText(); + + auto paint_record = sk_make_sp<PaintOpBuffer>(); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(SK_ColorGREEN); + paint_record->push<DrawTextBlobOp>( + BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags); + auto paint_record_filter = sk_make_sp<RecordPaintFilter>(paint_record, SkRect::MakeWH(100, 100)); - auto display_item_list = base::MakeRefCounted<DisplayItemList>(); - display_item_list->StartPaint(); - display_item_list->push<ScaleOp>(2.f, 2.f); - PaintFlags shader_flags; - shader_flags.setImageFilter(paint_record_filter); - display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags); - display_item_list->EndPaintOfUnpaired(options.full_raster_rect); - display_item_list->Finalize(); - - auto actual = Raster(display_item_list, options); - auto expected = RasterExpectedBitmap(display_item_list, options); - ExpectEquals(actual, expected); - } + auto display_item_list = base::MakeRefCounted<DisplayItemList>(); + display_item_list->StartPaint(); + display_item_list->push<ScaleOp>(2.f, 2.f); + PaintFlags shader_flags; + shader_flags.setImageFilter(paint_record_filter); + display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags); + display_item_list->EndPaintOfUnpaired(options.full_raster_rect); + display_item_list->Finalize(); + + auto actual = Raster(display_item_list, options); + auto expected = RasterExpectedBitmap(display_item_list, options); + ExpectEquals(actual, expected); + } }; - + TEST_P(OopRecordFilterPixelTest, FilterWithTextScaled) { RunTest(); } @@ -1601,10 +1609,53 @@ TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) { ExpectEquals(actual, expected); } +class OopPathPixelTest : public OopPixelTest, + public ::testing::WithParamInterface<bool> { + public: + bool AllowInlining() const { return GetParam(); } + void RunTest() { + auto* ri = static_cast<gpu::raster::RasterImplementation*>( + raster_context_provider_->RasterInterface()); + size_t max_inlined_entry_size = + AllowInlining() ? std::numeric_limits<size_t>::max() : 0u; + ri->set_max_inlined_entry_size_for_testing(max_inlined_entry_size); + + RasterOptions options; + options.resource_size = gfx::Size(100, 100); + options.content_size = options.resource_size; + options.full_raster_rect = gfx::Rect(options.content_size); + options.playback_rect = options.full_raster_rect; + options.color_space = gfx::ColorSpace::CreateSRGB(); + + auto display_item_list = base::MakeRefCounted<DisplayItemList>(); + display_item_list->StartPaint(); + display_item_list->push<DrawColorOp>(SK_ColorWHITE, SkBlendMode::kSrc); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(SK_ColorGREEN); + SkPath path; + path.addCircle(20, 20, 10); + display_item_list->push<DrawPathOp>(path, flags); + flags.setColor(SK_ColorBLUE); + display_item_list->push<DrawRectOp>(SkRect::MakeWH(10, 10), flags); + display_item_list->EndPaintOfUnpaired(options.full_raster_rect); + display_item_list->Finalize(); + + auto expected = RasterExpectedBitmap(display_item_list, options); + auto actual = Raster(display_item_list, options); + ExpectEquals(actual, expected); + } +}; + +TEST_P(OopPathPixelTest, Basic) { + RunTest(); +} + INSTANTIATE_TEST_CASE_P(P, OopImagePixelTest, ::testing::Bool()); INSTANTIATE_TEST_CASE_P(P, OopClearPixelTest, ::testing::Bool()); INSTANTIATE_TEST_CASE_P(P, OopRecordShaderPixelTest, ::testing::Bool()); INSTANTIATE_TEST_CASE_P(P, OopRecordFilterPixelTest, ::testing::Bool()); +INSTANTIATE_TEST_CASE_P(P, OopPathPixelTest, ::testing::Bool()); } // namespace } // namespace cc diff --git a/chromium/cc/paint/paint_cache.cc b/chromium/cc/paint/paint_cache.cc new file mode 100644 index 00000000000..b3fad275dba --- /dev/null +++ b/chromium/cc/paint/paint_cache.cc @@ -0,0 +1,126 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/paint/paint_cache.h" + +#include "base/containers/flat_set.h" +#include "base/no_destructor.h" +#include "base/synchronization/lock.h" + +namespace cc { +namespace { + +template <typename T> +void EraseFromMap(T* map, size_t n, const volatile PaintCacheId* ids) { + for (size_t i = 0; i < n; ++i) { + auto id = ids[i]; + map->erase(id); + } +} + +} // namespace + +ClientPaintCache::ClientPaintCache(size_t max_budget_bytes) + : cache_map_(CacheMap::NO_AUTO_EVICT), max_budget_(max_budget_bytes) {} +ClientPaintCache::~ClientPaintCache() = default; + +bool ClientPaintCache::Get(PaintCacheDataType type, PaintCacheId id) { + return cache_map_.Get(std::make_pair(type, id)) != cache_map_.end(); +} + +void ClientPaintCache::Put(PaintCacheDataType type, + PaintCacheId id, + size_t size) { + auto key = std::make_pair(type, id); + DCHECK(cache_map_.Peek(key) == cache_map_.end()); + + pending_entries_->push_back(key); + cache_map_.Put(key, size); + bytes_used_ += size; +} + +template <typename Iterator> +void ClientPaintCache::EraseFromMap(Iterator it) { + DCHECK_GE(bytes_used_, it->second); + bytes_used_ -= it->second; + cache_map_.Erase(it); +} + +void ClientPaintCache::FinalizePendingEntries() { + pending_entries_->clear(); +} + +void ClientPaintCache::AbortPendingEntries() { + for (const auto& entry : pending_entries_.container()) { + auto it = cache_map_.Peek(entry); + DCHECK(it != cache_map_.end()); + EraseFromMap(it); + } + pending_entries_->clear(); +} + +void ClientPaintCache::Purge(PurgedData* purged_data) { + DCHECK(pending_entries_->empty()); + + while (bytes_used_ > max_budget_) { + auto it = cache_map_.rbegin(); + PaintCacheDataType type = it->first.first; + PaintCacheId id = it->first.second; + + EraseFromMap(it); + (*purged_data)[static_cast<uint32_t>(type)].push_back(id); + } +} + +bool ClientPaintCache::PurgeAll() { + DCHECK(pending_entries_->empty()); + + bool has_data = !cache_map_.empty(); + cache_map_.Clear(); + bytes_used_ = 0u; + return has_data; +} + +ServicePaintCache::ServicePaintCache() = default; +ServicePaintCache::~ServicePaintCache() = default; + +void ServicePaintCache::PutTextBlob(PaintCacheId id, sk_sp<SkTextBlob> blob) { + cached_blobs_.emplace(id, std::move(blob)); +} + +sk_sp<SkTextBlob> ServicePaintCache::GetTextBlob(PaintCacheId id) { + auto it = cached_blobs_.find(id); + return it == cached_blobs_.end() ? nullptr : it->second; +} + +void ServicePaintCache::PutPath(PaintCacheId id, SkPath path) { + cached_paths_.emplace(id, std::move(path)); +} + +SkPath* ServicePaintCache::GetPath(PaintCacheId id) { + auto it = cached_paths_.find(id); + return it == cached_paths_.end() ? nullptr : &it->second; +} + +void ServicePaintCache::Purge(PaintCacheDataType type, + size_t n, + const volatile PaintCacheId* ids) { + switch (type) { + case PaintCacheDataType::kTextBlob: + EraseFromMap(&cached_blobs_, n, ids); + return; + case PaintCacheDataType::kPath: + EraseFromMap(&cached_paths_, n, ids); + return; + } + + NOTREACHED(); +} + +void ServicePaintCache::PurgeAll() { + cached_blobs_.clear(); + cached_paths_.clear(); +} + +} // namespace cc diff --git a/chromium/cc/paint/paint_cache.h b/chromium/cc/paint/paint_cache.h new file mode 100644 index 00000000000..10356eee5cb --- /dev/null +++ b/chromium/cc/paint/paint_cache.h @@ -0,0 +1,119 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_PAINT_PAINT_CACHE_H_ +#define CC_PAINT_PAINT_CACHE_H_ + +#include <map> +#include <set> + +#include "base/containers/mru_cache.h" +#include "base/containers/stack_container.h" +#include "cc/paint/paint_export.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkTextBlob.h" + +namespace cc { + +// PaintCache is used to cache high frequency small paint data types, like +// SkTextBlob and SkPath in the GPU service. The ClientPaintCache budgets and +// controls the cache state in the ServicePaintCache, regularly purging old +// entries returned in ClientPaintCache::Purge from the service side cache. In +// addition to this, the complete cache is cleared during the raster context +// idle cleanup. This effectively means that the cache budget is used as working +// memory that is only kept while we are actively rasterizing. +// +// The entries are serialized by the caller during paint op serialization, and +// the cache assumes the deserialization and purging to be done in order for +// accurately tracking the service side state in ServicePaintCache. +// +// Note that while TransferCache should be used for large data types that would +// benefit from a shared cache budgeted across all clients, using a client +// controlled PaintCache with a tighter budget is better for these data types +// since it avoids the need for cross-process ref-counting required by the +// TransferCache. + +using PaintCacheId = uint32_t; +using PaintCacheIds = std::vector<PaintCacheId>; +enum class PaintCacheDataType : uint32_t { kTextBlob, kPath, kLast = kPath }; +constexpr size_t PaintCacheDataTypeCount = + static_cast<uint32_t>(PaintCacheDataType::kLast) + 1u; + +class CC_PAINT_EXPORT ClientPaintCache { + public: + explicit ClientPaintCache(size_t max_budget_bytes); + ~ClientPaintCache(); + + bool Get(PaintCacheDataType type, PaintCacheId id); + void Put(PaintCacheDataType type, PaintCacheId id, size_t size); + + // Populates |purged_data| with the list of ids which should be purged from + // the ServicePaintCache. + using PurgedData = PaintCacheIds[PaintCacheDataTypeCount]; + void Purge(PurgedData* purged_data); + + // Finalize the state of pending entries, which were sent to the service-side + // cache. + void FinalizePendingEntries(); + + // Notifies that the pending entries were not sent to the service-side cache + // and should be discarded. + void AbortPendingEntries(); + + // Notifies that all entries should be purged from the ServicePaintCache. + // Returns true if any entries were evicted from this call. + bool PurgeAll(); + + size_t bytes_used() const { return bytes_used_; } + + private: + using CacheKey = std::pair<PaintCacheDataType, PaintCacheId>; + using CacheMap = base::MRUCache<CacheKey, size_t>; + + template <typename Iterator> + void EraseFromMap(Iterator it); + + CacheMap cache_map_; + const size_t max_budget_; + size_t bytes_used_ = 0u; + + // List of entries added to the map but not committed since we might fail to + // send them to the service-side cache. This is necessary to ensure we + // maintain an accurate mirror of the service-side state. + base::StackVector<CacheKey, 1> pending_entries_; + + DISALLOW_COPY_AND_ASSIGN(ClientPaintCache); +}; + +class CC_PAINT_EXPORT ServicePaintCache { + public: + ServicePaintCache(); + ~ServicePaintCache(); + + // Stores the |blob| received from the client in the cache. + void PutTextBlob(PaintCacheId id, sk_sp<SkTextBlob> blob); + + // Retrieves an entry for |id| stored in the cache. Or nullptr if the entry + // is not found. + sk_sp<SkTextBlob> GetTextBlob(PaintCacheId id); + + void PutPath(PaintCacheId, SkPath path); + SkPath* GetPath(PaintCacheId id); + + void Purge(PaintCacheDataType type, + size_t n, + const volatile PaintCacheId* ids); + void PurgeAll(); + bool empty() const { return cached_blobs_.empty() && cached_paths_.empty(); } + + private: + using BlobMap = std::map<PaintCacheId, sk_sp<SkTextBlob>>; + BlobMap cached_blobs_; + using PathMap = std::map<PaintCacheId, SkPath>; + PathMap cached_paths_; +}; + +} // namespace cc + +#endif // CC_PAINT_PAINT_CACHE_H_ diff --git a/chromium/cc/paint/paint_cache_unittest.cc b/chromium/cc/paint/paint_cache_unittest.cc new file mode 100644 index 00000000000..ea4e9b6175f --- /dev/null +++ b/chromium/cc/paint/paint_cache_unittest.cc @@ -0,0 +1,131 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/paint/paint_cache.h" + +#include "base/stl_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +constexpr size_t kDefaultBudget = 1024u; + +sk_sp<SkTextBlob> CreateBlob() { + SkFont font; + font.setTypeface(SkTypeface::MakeDefault()); + + SkTextBlobBuilder builder; + int glyph_count = 5; + const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f, nullptr); + // allocRun() allocates only the glyph buffer. + std::fill(run.glyphs, run.glyphs + glyph_count, 0); + return builder.make(); +} + +SkPath CreatePath() { + SkPath path; + path.addCircle(2, 2, 5); + return path; +} + +class PaintCacheTest : public ::testing::TestWithParam<uint32_t> { + public: + PaintCacheDataType GetType() { + return static_cast<PaintCacheDataType>(GetParam()); + } +}; + +TEST_P(PaintCacheTest, ClientBasic) { + ClientPaintCache client_cache(kDefaultBudget); + EXPECT_FALSE(client_cache.Get(GetType(), 1u)); + client_cache.Put(GetType(), 1u, 1u); + EXPECT_TRUE(client_cache.Get(GetType(), 1u)); +} + +TEST_P(PaintCacheTest, ClientPurgeForBudgeting) { + ClientPaintCache client_cache(kDefaultBudget); + client_cache.Put(GetType(), 1u, kDefaultBudget - 100); + client_cache.Put(GetType(), 2u, kDefaultBudget); + client_cache.Put(GetType(), 3u, kDefaultBudget); + EXPECT_EQ(client_cache.bytes_used(), 3 * kDefaultBudget - 100); + client_cache.FinalizePendingEntries(); + + ClientPaintCache::PurgedData purged_data; + client_cache.Purge(&purged_data); + EXPECT_EQ(client_cache.bytes_used(), kDefaultBudget); + const auto& ids = purged_data[static_cast<uint32_t>(GetType())]; + ASSERT_EQ(ids.size(), 2u); + EXPECT_EQ(ids[0], 1u); + EXPECT_EQ(ids[1], 2u); + + EXPECT_FALSE(client_cache.Get(GetType(), 1u)); + EXPECT_FALSE(client_cache.Get(GetType(), 2u)); + EXPECT_TRUE(client_cache.Get(GetType(), 3u)); +} + +TEST_P(PaintCacheTest, ClientPurgeAll) { + ClientPaintCache client_cache(kDefaultBudget); + client_cache.Put(GetType(), 1u, 1u); + EXPECT_EQ(client_cache.bytes_used(), 1u); + client_cache.FinalizePendingEntries(); + + EXPECT_TRUE(client_cache.PurgeAll()); + EXPECT_EQ(client_cache.bytes_used(), 0u); + EXPECT_FALSE(client_cache.PurgeAll()); +} + +TEST_P(PaintCacheTest, CommitPendingEntries) { + ClientPaintCache client_cache(kDefaultBudget); + + client_cache.Put(GetType(), 1u, 1u); + EXPECT_TRUE(client_cache.Get(GetType(), 1u)); + client_cache.AbortPendingEntries(); + EXPECT_FALSE(client_cache.Get(GetType(), 1u)); + + client_cache.Put(GetType(), 1u, 1u); + client_cache.FinalizePendingEntries(); + EXPECT_TRUE(client_cache.Get(GetType(), 1u)); +} + +TEST_P(PaintCacheTest, ServiceBasic) { + ServicePaintCache service_cache; + switch (GetType()) { + case PaintCacheDataType::kTextBlob: { + auto blob = CreateBlob(); + auto id = blob->uniqueID(); + EXPECT_EQ(nullptr, service_cache.GetTextBlob(id)); + service_cache.PutTextBlob(id, blob); + EXPECT_EQ(blob, service_cache.GetTextBlob(id)); + service_cache.Purge(GetType(), 1, &id); + EXPECT_EQ(nullptr, service_cache.GetTextBlob(id)); + + service_cache.PutTextBlob(id, blob); + } break; + case PaintCacheDataType::kPath: { + auto path = CreatePath(); + auto id = path.getGenerationID(); + EXPECT_EQ(nullptr, service_cache.GetPath(id)); + service_cache.PutPath(id, path); + EXPECT_EQ(path, *service_cache.GetPath(id)); + service_cache.Purge(GetType(), 1, &id); + EXPECT_EQ(nullptr, service_cache.GetPath(id)); + + service_cache.PutPath(id, path); + } break; + } + + EXPECT_FALSE(service_cache.empty()); + service_cache.PurgeAll(); + EXPECT_TRUE(service_cache.empty()); +} + +INSTANTIATE_TEST_CASE_P( + P, + PaintCacheTest, + ::testing::Range(static_cast<uint32_t>(0), + static_cast<uint32_t>(PaintCacheDataType::kLast))); + +} // namespace +} // namespace cc diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h index 53bde682c34..80a6915472d 100644 --- a/chromium/cc/paint/paint_canvas.h +++ b/chromium/cc/paint/paint_canvas.h @@ -11,16 +11,29 @@ #include "build/build_config.h" #include "cc/paint/paint_export.h" #include "cc/paint/paint_image.h" -#include "cc/paint/paint_text_blob.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkTextBlob.h" namespace cc { - +class SkottieWrapper; class PaintFlags; class PaintOpBuffer; using PaintRecord = PaintOpBuffer; +// PaintCanvas is the cc/paint wrapper of SkCanvas. It has a more restricted +// interface than SkCanvas (trimmed back to only what Chrome uses). Its reason +// for existence is so that it can do custom serialization logic into a +// PaintOpBuffer which (unlike SkPicture) is mutable, handles image replacement, +// and can be serialized in custom ways (such as using the transfer cache). +// +// PaintCanvas is usually implemented by either: +// (1) SkiaPaintCanvas, which is backed by an SkCanvas, usually for rasterizing. +// (2) RecordPaintCanvas, which records paint commands into a PaintOpBuffer. +// +// SkiaPaintCanvas allows callers to go from PaintCanvas to SkCanvas (or +// PaintRecord to SkPicture), but this is a one way trip. There is no way to go +// from SkCanvas to PaintCanvas or from SkPicture back into PaintRecord. class CC_PAINT_EXPORT PaintCanvas { public: PaintCanvas() {} @@ -133,7 +146,14 @@ class CC_PAINT_EXPORT PaintCanvas { const PaintFlags* flags, SrcRectConstraint constraint) = 0; - virtual void drawTextBlob(scoped_refptr<PaintTextBlob> blob, + // Draws the frame of the |skottie| animation specified by the normalized time + // t [0->first frame..1->last frame] at the destination bounds given by |dst| + // onto the canvas. + virtual void drawSkottie(scoped_refptr<SkottieWrapper> skottie, + const SkRect& dst, + float t) = 0; + + virtual void drawTextBlob(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) = 0; diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc index 0e0bd00822e..2cd34c8beec 100644 --- a/chromium/cc/paint/paint_filter.cc +++ b/chromium/cc/paint/paint_filter.cc @@ -668,7 +668,7 @@ ImagePaintFilter::ImagePaintFilter(PaintImage image, const SkRect& src_rect, const SkRect& dst_rect, SkFilterQuality filter_quality) - : PaintFilter(kType, nullptr, image.IsLazyGenerated()), + : PaintFilter(kType, nullptr, !image.IsTextureBacked()), image_(std::move(image)), src_rect_(src_rect), dst_rect_(dst_rect), diff --git a/chromium/cc/paint/paint_filter_unittest.cc b/chromium/cc/paint/paint_filter_unittest.cc index de1ea45132c..a83438648b4 100644 --- a/chromium/cc/paint/paint_filter_unittest.cc +++ b/chromium/cc/paint/paint_filter_unittest.cc @@ -33,7 +33,7 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type, if (has_discardable_images) image = CreateDiscardablePaintImage(gfx::Size(100, 100)); else - image = CreateBitmapImage(gfx::Size(100, 100)); + image = CreateNonDiscardablePaintImage(gfx::Size(100, 100)); auto image_filter = sk_make_sp<ImagePaintFilter>( image, SkRect::MakeWH(100.f, 100.f), SkRect::MakeWH(100.f, 100.f), diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc index 41b561ff738..c0ff3a6aa47 100644 --- a/chromium/cc/paint/paint_flags.cc +++ b/chromium/cc/paint/paint_flags.cc @@ -25,7 +25,7 @@ PaintFlags::PaintFlags() { bitfields_.join_type_ = SkPaint::kDefault_Join; bitfields_.style_ = SkPaint::kFill_Style; bitfields_.text_encoding_ = SkPaint::kUTF8_TextEncoding; - bitfields_.hinting_ = SkPaint::kNormal_Hinting; + bitfields_.hinting_ = static_cast<unsigned>(SkFontHinting::kNormal); bitfields_.filter_quality_ = SkFilterQuality::kNone_SkFilterQuality; static_assert(sizeof(bitfields_) <= sizeof(bitfields_uint_), @@ -146,11 +146,30 @@ SkPaint PaintFlags::ToSkPaint() const { paint.setStrokeJoin(static_cast<SkPaint::Join>(getStrokeJoin())); paint.setStyle(static_cast<SkPaint::Style>(getStyle())); paint.setTextEncoding(static_cast<SkPaint::TextEncoding>(getTextEncoding())); - paint.setHinting(static_cast<SkPaint::Hinting>(getHinting())); + paint.setHinting(static_cast<SkFontHinting>(getHinting())); paint.setFilterQuality(getFilterQuality()); return paint; } +SkFont PaintFlags::ToSkFont() const { + SkFont font; + font.setTypeface(typeface_); + font.setSize(text_size_); + font.setHinting(static_cast<SkFontHinting>(getHinting())); + font.setForceAutoHinting(isAutohinted()); + font.setSubpixel(isSubpixelText()); + if (isAntiAlias()) { + if (isLCDRenderText()) { + font.setEdging(SkFont::Edging::kSubpixelAntiAlias); + } else { + font.setEdging(SkFont::Edging::kAntiAlias); + } + } else { + font.setEdging(SkFont::Edging::kAlias); + } + return font; +} + bool PaintFlags::IsValid() const { return PaintOp::IsValidPaintFlagsSkBlendMode(getBlendMode()); } diff --git a/chromium/cc/paint/paint_flags.h b/chromium/cc/paint/paint_flags.h index a132fd702bd..fda9cc5ba8d 100644 --- a/chromium/cc/paint/paint_flags.h +++ b/chromium/cc/paint/paint_flags.h @@ -11,6 +11,8 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkDrawLooper.h" +#include "third_party/skia/include/core/SkFont.h" +#include "third_party/skia/include/core/SkFontTypes.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" #include "third_party/skia/include/core/SkPaint.h" @@ -18,8 +20,6 @@ #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkTypeface.h" -class SkPaint; - namespace cc { class PaintFilter; @@ -62,12 +62,6 @@ class CC_PAINT_EXPORT PaintFlags { ALWAYS_INLINE void setAntiAlias(bool aa) { SetInternalFlag(aa, SkPaint::kAntiAlias_Flag); } - ALWAYS_INLINE bool isVerticalText() const { - return !!(bitfields_.flags_ & SkPaint::kVerticalText_Flag); - } - ALWAYS_INLINE void setVerticalText(bool vertical) { - SetInternalFlag(vertical, SkPaint::kVerticalText_Flag); - } ALWAYS_INLINE bool isSubpixelText() const { return !!(bitfields_.flags_ & SkPaint::kSubpixelText_Flag); } @@ -81,10 +75,11 @@ class CC_PAINT_EXPORT PaintFlags { SetInternalFlag(lcd_text, SkPaint::kLCDRenderText_Flag); } enum Hinting { - kNo_Hinting = SkPaint::kNo_Hinting, - kSlight_Hinting = SkPaint::kSlight_Hinting, - kNormal_Hinting = SkPaint::kNormal_Hinting, //!< this is the default - kFull_Hinting = SkPaint::kFull_Hinting + kNo_Hinting = static_cast<unsigned>(SkFontHinting::kNone), + kSlight_Hinting = static_cast<unsigned>(SkFontHinting::kSlight), + kNormal_Hinting = + static_cast<unsigned>(SkFontHinting::kNormal), //!< this is the default + kFull_Hinting = static_cast<unsigned>(SkFontHinting::kFull) }; ALWAYS_INLINE Hinting getHinting() const { return static_cast<Hinting>(bitfields_.hinting_); @@ -214,6 +209,7 @@ class CC_PAINT_EXPORT PaintFlags { bool SupportsFoldingAlpha() const; SkPaint ToSkPaint() const; + SkFont ToSkFont() const; bool IsValid() const; bool operator==(const PaintFlags& other) const; diff --git a/chromium/cc/paint/paint_font.cc b/chromium/cc/paint/paint_font.cc deleted file mode 100644 index 96818286705..00000000000 --- a/chromium/cc/paint/paint_font.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/paint/paint_font.h" - -#include "cc/paint/paint_export.h" -#include "third_party/skia/include/core/SkPaint.h" - -namespace cc { - -PaintFont::PaintFont() = default; -PaintFont::~PaintFont() = default; - -void PaintFont::SetTextEncoding(SkPaint::TextEncoding encoding) { - sk_paint_.setTextEncoding(encoding); -} - -void PaintFont::SetAntiAlias(bool use_anti_alias) { - sk_paint_.setAntiAlias(use_anti_alias); -} - -void PaintFont::SetHinting(SkPaint::Hinting hinting) { - sk_paint_.setHinting(hinting); -} - -void PaintFont::SetEmbeddedBitmapText(bool use_bitmaps) { - sk_paint_.setEmbeddedBitmapText(use_bitmaps); -} - -void PaintFont::SetAutohinted(bool use_auto_hint) { - sk_paint_.setAutohinted(use_auto_hint); -} - -void PaintFont::SetLcdRenderText(bool lcd_text) { - sk_paint_.setLCDRenderText(lcd_text); -} - -void PaintFont::SetSubpixelText(bool subpixel_text) { - sk_paint_.setSubpixelText(subpixel_text); -} - -void PaintFont::SetTextSize(SkScalar size) { - sk_paint_.setTextSize(size); -} - -void PaintFont::SetTypeface(sk_sp<SkTypeface> typeface) { - typeface_ = typeface; - sk_paint_.setTypeface(typeface); -} - -void PaintFont::SetFakeBoldText(bool bold_text) { - sk_paint_.setFakeBoldText(bold_text); -} - -void PaintFont::SetTextSkewX(SkScalar skew) { - sk_paint_.setTextSkewX(skew); -} - -void PaintFont::SetFlags(uint32_t flags) { - sk_paint_.setFlags(flags); -} - -} // namespace cc diff --git a/chromium/cc/paint/paint_font.h b/chromium/cc/paint/paint_font.h deleted file mode 100644 index 3b34ac404fb..00000000000 --- a/chromium/cc/paint/paint_font.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_PAINT_PAINT_FONT_H_ -#define CC_PAINT_PAINT_FONT_H_ - -#include "cc/paint/paint_export.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/include/core/SkTypeface.h" - -namespace cc { - -class CC_PAINT_EXPORT PaintFont { - public: - PaintFont(); - ~PaintFont(); - - void SetTextEncoding(SkPaint::TextEncoding encoding); - void SetAntiAlias(bool use_anti_alias); - void SetHinting(SkPaint::Hinting hinting); - void SetEmbeddedBitmapText(bool use_bitmaps); - void SetAutohinted(bool use_auto_hint); - void SetLcdRenderText(bool lcd_text); - void SetSubpixelText(bool subpixel_text); - void SetTextSize(SkScalar size); - void SetTypeface(sk_sp<SkTypeface> typeface); - void SetFakeBoldText(bool bold_text); - void SetTextSkewX(SkScalar skew); - void SetFlags(uint32_t flags); - - uint32_t flags() const { return sk_paint_.getFlags(); } - - const sk_sp<SkTypeface> typeface() const { return typeface_; } - const SkPaint& ToSkPaint() const { return sk_paint_; } - - private: - sk_sp<SkTypeface> typeface_; - SkPaint sk_paint_; -}; - -} // namespace cc - -#endif // CC_PAINT_PAINT_FONT_H_ diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h index efde11152ae..0684c2d80c6 100644 --- a/chromium/cc/paint/paint_image.h +++ b/chromium/cc/paint/paint_image.h @@ -21,9 +21,23 @@ class PaintImageGenerator; class PaintOpBuffer; using PaintRecord = PaintOpBuffer; -// A representation of an image for the compositor. -// Note that aside from default construction, it can only be constructed using a -// PaintImageBuilder, or copied/moved into using operator=. +// A representation of an image for the compositor. This is the most abstract +// form of images, and represents what is known at paint time. Note that aside +// from default construction, it can only be constructed using a +// PaintImageBuilder, or copied/moved into using operator=. PaintImage can +// be backed by different kinds of content, such as a lazy generator, a paint +// record, a bitmap, or a texture. +// +// If backed by a generator, this image may not be decoded and information like +// the animation frame, the target colorspace, or the scale at which it will be +// used are not known yet. A DrawImage is a PaintImage with those decisions +// known but that might not have been decoded yet. A DecodedDrawImage is a +// DrawImage that has been decoded/scaled/uploaded with all of those parameters +// applied. +// +// The PaintImage -> DrawImage -> DecodedDrawImage -> PaintImage (via SkImage) +// path can be used to create a PaintImage that is snapshotted at a particular +// scale or animation frame. class CC_PAINT_EXPORT PaintImage { public: using Id = int; @@ -162,6 +176,7 @@ class CC_PAINT_EXPORT PaintImage { uint32_t unique_id() const { return GetSkImage()->uniqueID(); } explicit operator bool() const { return !!GetSkImage(); } bool IsLazyGenerated() const { return GetSkImage()->isLazyGenerated(); } + bool IsTextureBacked() const { return GetSkImage()->isTextureBacked(); } int width() const { return GetSkImage()->width(); } int height() const { return GetSkImage()->height(); } SkColorSpace* color_space() const { return GetSkImage()->colorSpace(); } diff --git a/chromium/cc/paint/paint_image_generator.h b/chromium/cc/paint/paint_image_generator.h index 95189c7da90..d0ce1c75c02 100644 --- a/chromium/cc/paint/paint_image_generator.h +++ b/chromium/cc/paint/paint_image_generator.h @@ -14,7 +14,8 @@ #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkSize.h" -#include "third_party/skia/include/core/SkYUVSizeInfo.h" +#include "third_party/skia/include/core/SkYUVAIndex.h" +#include "third_party/skia/include/core/SkYUVASizeInfo.h" namespace cc { @@ -44,21 +45,25 @@ class CC_PAINT_EXPORT PaintImageGenerator : public SkRefCnt { // Returns true if the generator supports YUV decoding, providing the output // information in |info| and |color_space|. - virtual bool QueryYUV8(SkYUVSizeInfo* info, - SkYUVColorSpace* color_space) const = 0; + virtual bool QueryYUVA8(SkYUVASizeInfo* info, + SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + SkYUVColorSpace* color_space) const = 0; // Decodes to YUV into the provided |planes| for each of the Y, U, and V // planes, and returns true on success. The method should only be used if - // QueryYUV8 returns true. - // |info| needs to exactly match the values returned by the query, except the - // WidthBytes may be larger than the recommendation (but not smaller). + // QueryYUVA8 returns true. + // |info| and |indices| need to exactly match the values returned by the + // query, except the info.fWidthBytes may be larger than the recommendation + // (but not smaller). // // TODO(khushalsagar): |lazy_pixel_ref| is only present for // DecodingImageGenerator tracing needs. Remove it. - virtual bool GetYUV8Planes(const SkYUVSizeInfo& info, - void* planes[3], - size_t frame_index, - uint32_t lazy_pixel_ref) = 0; + virtual bool GetYUVA8Planes( + const SkYUVASizeInfo& info, + const SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + void* planes[3], + size_t frame_index, + uint32_t lazy_pixel_ref) = 0; // Returns the smallest size that is at least as big as the requested size, // such that we can decode to exactly that scale. diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc index 13867d477a2..7ae8135f509 100644 --- a/chromium/cc/paint/paint_op_buffer.cc +++ b/chromium/cc/paint/paint_op_buffer.cc @@ -65,6 +65,7 @@ SkRect AdjustSrcRectForScale(SkRect original, SkSize scale_adjustment) { M(DrawRecordOp) \ M(DrawRectOp) \ M(DrawRRectOp) \ + M(DrawSkottieOp) \ M(DrawTextBlobOp) \ M(NoopOp) \ M(RestoreOp) \ @@ -263,6 +264,8 @@ std::string PaintOpTypeToString(PaintOpType type) { return "DrawRect"; case PaintOpType::DrawRRect: return "DrawRRect"; + case PaintOpType::DrawSkottie: + return "DrawSkottie"; case PaintOpType::DrawTextBlob: return "DrawTextBlob"; case PaintOpType::Noop: @@ -323,6 +326,7 @@ PlaybackParams& PlaybackParams::operator=(const PlaybackParams& other) = PaintOp::SerializeOptions::SerializeOptions( ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkCanvas* canvas, SkStrikeServer* strike_server, SkColorSpace* color_space, @@ -333,6 +337,7 @@ PaintOp::SerializeOptions::SerializeOptions( const SkMatrix& original_ctm) : image_provider(image_provider), transfer_cache(transfer_cache), + paint_cache(paint_cache), canvas(canvas), strike_server(strike_server), color_space(color_space), @@ -349,8 +354,11 @@ PaintOp::SerializeOptions& PaintOp::SerializeOptions::operator=( PaintOp::DeserializeOptions::DeserializeOptions( TransferCacheDeserializeHelper* transfer_cache, + ServicePaintCache* paint_cache, SkStrikeClient* strike_client) - : transfer_cache(transfer_cache), strike_client(strike_client) {} + : transfer_cache(transfer_cache), + paint_cache(paint_cache), + strike_client(strike_client) {} size_t AnnotateOp::Serialize(const PaintOp* base_op, void* memory, @@ -578,6 +586,16 @@ size_t DrawRRectOp::Serialize(const PaintOp* base_op, return helper.size(); } +size_t DrawSkottieOp::Serialize(const PaintOp* op, + void* memory, + size_t size, + const SerializeOptions& options) { + // TODO(malaykeshav): these must be flattened. Serializing this will not do + // anything. See https://crbug.com/894635 + NOTREACHED(); + return 0u; +} + size_t DrawTextBlobOp::Serialize(const PaintOp* base_op, void* memory, size_t size, @@ -987,6 +1005,16 @@ PaintOp* DrawRRectOp::Deserialize(const volatile void* input, return op; } +PaintOp* DrawSkottieOp::Deserialize(const volatile void* input, + size_t input_size, + void* output, + size_t output_size, + const DeserializeOptions& options) { + // TODO(malaykeshav): these must be flattened and not sent directly. + // See https://crbug.com/894635 + return nullptr; +} + PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input, size_t input_size, void* output, @@ -1318,12 +1346,18 @@ void DrawRRectOp::RasterWithFlags(const DrawRRectOp* op, canvas->drawRRect(op->rrect, paint); } +void DrawSkottieOp::Raster(const DrawSkottieOp* op, + SkCanvas* canvas, + const PlaybackParams& params) { + op->skottie->Draw(canvas, op->t, op->dst); +} + void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op, const PaintFlags* flags, SkCanvas* canvas, const PlaybackParams& params) { SkPaint paint = flags->ToSkPaint(); - canvas->drawTextBlob(op->blob->ToSkTextBlob().get(), op->x, op->y, paint); + canvas->drawTextBlob(op->blob.get(), op->x, op->y, paint); } void RestoreOp::Raster(const RestoreOp* op, @@ -1702,6 +1736,21 @@ bool DrawRRectOp::AreEqual(const PaintOp* base_left, return true; } +bool DrawSkottieOp::AreEqual(const PaintOp* base_left, + const PaintOp* base_right) { + auto* left = static_cast<const DrawSkottieOp*>(base_left); + auto* right = static_cast<const DrawSkottieOp*>(base_right); + DCHECK(left->IsValid()); + DCHECK(right->IsValid()); + // TODO(malaykeshav): Verify the skottie objects of each PaintOb are equal + // based on the serialized bytes. + if (left->t != right->t) + return false; + if (!AreSkRectsEqual(left->dst, right->dst)) + return false; + return true; +} + bool DrawTextBlobOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) { auto* left = static_cast<const DrawTextBlobOp*>(base_left); @@ -1715,13 +1764,9 @@ bool DrawTextBlobOp::AreEqual(const PaintOp* base_left, if (!AreEqualEvenIfNaN(left->y, right->y)) return false; - DCHECK(*left->blob); - DCHECK(*right->blob); - SkSerialProcs default_procs; - return left->blob->ToSkTextBlob() - ->serialize(default_procs) - ->equals(right->blob->ToSkTextBlob()->serialize(default_procs).get()); + return left->blob->serialize(default_procs) + ->equals(right->blob->serialize(default_procs).get()); } bool NoopOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) { @@ -1947,10 +1992,15 @@ bool PaintOp::GetBounds(const PaintOp* op, SkRect* rect) { } case PaintOpType::DrawRecord: return false; + case PaintOpType::DrawSkottie: { + auto* skottie_op = static_cast<const DrawSkottieOp*>(op); + *rect = skottie_op->dst; + rect->sort(); + return true; + } case PaintOpType::DrawTextBlob: { auto* text_op = static_cast<const DrawTextBlobOp*>(op); - *rect = text_op->blob->ToSkTextBlob()->bounds().makeOffset(text_op->x, - text_op->y); + *rect = text_op->blob->bounds().makeOffset(text_op->x, text_op->y); rect->sort(); return true; } @@ -2087,9 +2137,7 @@ DrawImageOp::DrawImageOp(const PaintImage& image, top(top) {} bool DrawImageOp::HasDiscardableImages() const { - // TODO(khushalsagar): Callers should not be able to change the lazy generated - // state for a PaintImage. - return image && image.IsLazyGenerated(); + return image && !image.IsTextureBacked(); } DrawImageOp::~DrawImageOp() = default; @@ -2108,7 +2156,7 @@ DrawImageRectOp::DrawImageRectOp(const PaintImage& image, constraint(constraint) {} bool DrawImageRectOp::HasDiscardableImages() const { - return image && image.IsLazyGenerated(); + return image && !image.IsTextureBacked(); } DrawImageRectOp::~DrawImageRectOp() = default; @@ -2126,17 +2174,26 @@ size_t DrawRecordOp::AdditionalOpCount() const { return record->total_op_count(); } +DrawSkottieOp::DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie, + SkRect dst, + float t) + : PaintOp(kType), skottie(std::move(skottie)), dst(dst), t(t) {} + +DrawSkottieOp::DrawSkottieOp() : PaintOp(kType) {} + +DrawSkottieOp::~DrawSkottieOp() = default; + bool DrawRecordOp::HasDiscardableImages() const { return record->HasDiscardableImages(); } DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {} -DrawTextBlobOp::DrawTextBlobOp(scoped_refptr<PaintTextBlob> paint_blob, +DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) - : PaintOpWithFlags(kType, flags), blob(std::move(paint_blob)), x(x), y(y) {} + : PaintOpWithFlags(kType, flags), blob(std::move(blob)), x(x), y(y) {} DrawTextBlobOp::~DrawTextBlobOp() = default; diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h index b65491d6ac1..a4a3ae89f72 100644 --- a/chromium/cc/paint/paint_op_buffer.h +++ b/chromium/cc/paint/paint_op_buffer.h @@ -22,6 +22,7 @@ #include "cc/paint/paint_canvas.h" #include "cc/paint/paint_export.h" #include "cc/paint/paint_flags.h" +#include "cc/paint/skottie_wrapper.h" #include "cc/paint/transfer_cache_deserialize_helper.h" #include "cc/paint/transfer_cache_serialize_helper.h" #include "third_party/skia/include/core/SkColor.h" @@ -38,6 +39,8 @@ class SkStrikeServer; // PaintOpBuffer is a reimplementation of SkLiteDL. // See: third_party/skia/src/core/SkLiteDL.h. namespace cc { +class ClientPaintCache; +class ServicePaintCache; class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix { public: @@ -82,6 +85,7 @@ enum class PaintOpType : uint8_t { DrawRecord, DrawRect, DrawRRect, + DrawSkottie, DrawTextBlob, Noop, Restore, @@ -143,6 +147,7 @@ class CC_PAINT_EXPORT PaintOp { struct CC_PAINT_EXPORT SerializeOptions { SerializeOptions(ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkCanvas* canvas, SkStrikeServer* strike_server, SkColorSpace* color_space, @@ -157,6 +162,7 @@ class CC_PAINT_EXPORT PaintOp { // Required. ImageProvider* image_provider = nullptr; TransferCacheSerializeHelper* transfer_cache = nullptr; + ClientPaintCache* paint_cache = nullptr; SkCanvas* canvas = nullptr; SkStrikeServer* strike_server = nullptr; SkColorSpace* color_space = nullptr; @@ -174,10 +180,14 @@ class CC_PAINT_EXPORT PaintOp { struct CC_PAINT_EXPORT DeserializeOptions { DeserializeOptions(TransferCacheDeserializeHelper* transfer_cache, + ServicePaintCache* paint_cache, SkStrikeClient* strike_client); TransferCacheDeserializeHelper* transfer_cache = nullptr; - uint32_t raster_color_space_id = gfx::ColorSpace::kInvalidId; + ServicePaintCache* paint_cache = nullptr; SkStrikeClient* strike_client = nullptr; + uint32_t raster_color_space_id = gfx::ColorSpace::kInvalidId; + // Do a DumpWithoutCrashing when serialization fails. + bool crash_dump_on_failure = false; }; // Indicates how PaintImages are serialized. @@ -695,11 +705,34 @@ class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlags { DrawRRectOp() : PaintOpWithFlags(kType) {} }; +class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOp { + public: + static constexpr PaintOpType kType = PaintOpType::DrawSkottie; + static constexpr bool kIsDrawOp = true; + DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie, SkRect dst, float t); + ~DrawSkottieOp(); + static void Raster(const DrawSkottieOp* op, + SkCanvas* canvas, + const PlaybackParams& params); + bool IsValid() const { + return !!skottie && !dst.isEmpty() && t >= 0 && t <= 1.f; + } + static bool AreEqual(const PaintOp* left, const PaintOp* right); + HAS_SERIALIZATION_FUNCTIONS(); + + scoped_refptr<SkottieWrapper> skottie; + SkRect dst; + float t; + + private: + DrawSkottieOp(); +}; + class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags { public: static constexpr PaintOpType kType = PaintOpType::DrawTextBlob; static constexpr bool kIsDrawOp = true; - DrawTextBlobOp(scoped_refptr<PaintTextBlob> blob, + DrawTextBlobOp(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags); @@ -712,7 +745,7 @@ class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags { static bool AreEqual(const PaintOp* left, const PaintOp* right); HAS_SERIALIZATION_FUNCTIONS(); - scoped_refptr<PaintTextBlob> blob; + sk_sp<SkTextBlob> blob; SkScalar x; SkScalar y; diff --git a/chromium/cc/paint/paint_op_buffer_eq_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_eq_fuzzer.cc deleted file mode 100644 index 081744b7e7e..00000000000 --- a/chromium/cc/paint/paint_op_buffer_eq_fuzzer.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stddef.h> -#include <stdint.h> - -#include "cc/paint/paint_op_buffer.h" -#include "cc/test/paint_op_helper.h" -#include "cc/test/test_options_provider.h" -#include "third_party/skia/include/utils/SkNoDrawCanvas.h" - -// paint_op_buffer_eq_fuzzer deserializes and reserializes paint ops to -// make sure that this does not modify or incorrectly serialize them. -// This is intended to be a fuzzing correctness test. -// -// Compare this to paint_op_buffer_fuzzer which makes sure that deserializing -// ops and rasterizing those ops is safe. -// -// This test performs the following operation: -// -// serialized1 -> deserialized1 -> serialized2 -> deserialized2 -> serialized3 -// -// Ideally this test would compare serialized1 to serialized2, however: -// (1) Deserializing is a destructive process on bad input, e.g. SkMatrix -// that says it is identity will be clobbered to have identity values. -// (2) Padding for alignment is skipped and so serialized1 may have garbage. -// serialized2 and serialized3 are cleared to zero first. -// (3) Any internal allocated memory (e.g. DrawRecord ops) also will not -// be initialized to zero, and some ops memcpy when serializing or -// deserializing, and may copy some of this garbage. -// -// It'd be nice to be able to binary compare, but because of all the above -// reasons, this is impossible to do for all ops, so this test only does -// a logical comparison of deserialized1 and deserialized2, and verifies -// that serialized2 and serialized3 wrote the exact same number of bytes. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - const size_t kMaxSerializedSize = 1000000; - - SkNoDrawCanvas canvas(100, 100); - cc::TestOptionsProvider test_options_provider; - - // Need 4 bytes to be able to read the type/skip. - if (size < 4) - return 0; - - size_t serialized_size = reinterpret_cast<const cc::PaintOp*>(data)->skip; - if (serialized_size > kMaxSerializedSize) - return 0; - - // If the op has a skip that runs off the end of the input, then ignore. - if (serialized_size > size) - return 0; - - std::unique_ptr<char, base::AlignedFreeDeleter> deserialized1( - static_cast<char*>(base::AlignedAlloc(sizeof(cc::LargestPaintOp), - cc::PaintOpBuffer::PaintOpAlign))); - size_t bytes_read1 = 0; - cc::PaintOp* deserialized_op1 = cc::PaintOp::Deserialize( - data, size, deserialized1.get(), sizeof(cc::LargestPaintOp), &bytes_read1, - test_options_provider.deserialize_options()); - - // Failed to deserialize, so abort. - if (!deserialized_op1) - return 0; - - // DrawTextBlob ops contain two pieces of information: a text blob, and a - // vector of typefaces that are used in the blob. However, during - // deserialization we never need to reconstruct the vector of typefaces, since - // it is only used to reconstruct the blob directly. This, however, poses a - // problem for this fuzzer since we will then try to serialize the op again, - // resulting in an assert. The assert says that we don't have typefaces - // (serialized from the vector) that are required to serialize the text blob. - // The solution is to skip the equality fuzzer for DrawTextBlob ops. - // - // Normally the initial deserialization would also fail and we would early out - // above, since the transfer cache doesn't have any entries to reconstruct the - // text blob. However, Skia, given some data, seems to be able to construct an - // SkTextBlob without accessing the given cataloger. See crbug.com/798939 for - // an example of such a test case. - if (deserialized_op1->GetType() == cc::PaintOpType::DrawTextBlob) { - deserialized_op1->DestroyThis(); - return 0; - } - - // If we get to this point, then the op should be ok to serialize/deserialize - // and any failure is a dcheck. - std::unique_ptr<char, base::AlignedFreeDeleter> serialized2( - static_cast<char*>(base::AlignedAlloc(serialized_size, - cc::PaintOpBuffer::PaintOpAlign))); - memset(serialized2.get(), 0, serialized_size); - size_t written_bytes2 = - deserialized_op1->Serialize(serialized2.get(), serialized_size, - test_options_provider.serialize_options()); - CHECK_LE(written_bytes2, serialized_size); - - std::unique_ptr<char, base::AlignedFreeDeleter> deserialized2( - static_cast<char*>(base::AlignedAlloc(sizeof(cc::LargestPaintOp), - cc::PaintOpBuffer::PaintOpAlign))); - size_t bytes_read2 = 0; - cc::PaintOp* deserialized_op2 = cc::PaintOp::Deserialize( - data, size, deserialized2.get(), sizeof(cc::LargestPaintOp), &bytes_read2, - test_options_provider.deserialize_options()); - CHECK(deserialized_op2); - CHECK_EQ(bytes_read1, bytes_read2); - - std::unique_ptr<char, base::AlignedFreeDeleter> serialized3( - static_cast<char*>( - base::AlignedAlloc(written_bytes2, cc::PaintOpBuffer::PaintOpAlign))); - memset(serialized3.get(), 0, written_bytes2); - size_t written_bytes3 = - deserialized_op2->Serialize(serialized3.get(), written_bytes2, - test_options_provider.serialize_options()); - CHECK_EQ(written_bytes2, written_bytes3); - - CHECK(*deserialized_op1 == *deserialized_op2) - << "\n1: " << cc::PaintOpHelper::ToString(deserialized_op1) - << "\n2: " << cc::PaintOpHelper::ToString(deserialized_op2); - - deserialized_op1->DestroyThis(); - deserialized_op2->DestroyThis(); - - return 0; -} diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc index 9c82f148556..c91d62fbfa8 100644 --- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc +++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc @@ -6,6 +6,7 @@ #include <stdint.h> #include "base/command_line.h" +#include "cc/paint/paint_cache.h" #include "cc/paint/paint_op_buffer.h" #include "cc/test/transfer_cache_test_helper.h" #include "components/viz/test/test_context_provider.h" @@ -52,6 +53,7 @@ class FontSupport : public gpu::ServiceFontManager::Client { void Raster(scoped_refptr<viz::TestContextProvider> context_provider, SkStrikeClient* strike_client, + cc::ServicePaintCache* paint_cache, const uint8_t* data, size_t size) { const size_t kRasterDimension = 32; @@ -66,8 +68,8 @@ void Raster(scoped_refptr<viz::TestContextProvider> context_provider, cc::PlaybackParams params(nullptr, canvas->getTotalMatrix()); cc::TransferCacheTestHelper transfer_cache_helper; - cc::PaintOp::DeserializeOptions deserialize_options(&transfer_cache_helper, - strike_client); + cc::PaintOp::DeserializeOptions deserialize_options( + &transfer_cache_helper, paint_cache, strike_client); // Need 4 bytes to be able to read the type/skip. while (size >= 4) { @@ -116,6 +118,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FontSupport font_support; scoped_refptr<gpu::ServiceFontManager> font_manager( new gpu::ServiceFontManager(&font_support)); + cc::ServicePaintCache paint_cache; std::vector<SkDiscardableHandleId> locked_handles; if (bytes_for_fonts > 0u) { font_manager->Deserialize(reinterpret_cast<const char*>(data), @@ -127,16 +130,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { auto context_provider_no_support = viz::TestContextProvider::Create(); context_provider_no_support->BindToCurrentThread(); CHECK(!context_provider_no_support->GrContext()->supportsDistanceFieldText()); - Raster(context_provider_no_support, font_manager->strike_client(), data, - size); + Raster(context_provider_no_support, font_manager->strike_client(), + &paint_cache, data, size); auto context_provider_with_support = viz::TestContextProvider::Create( std::string("GL_OES_standard_derivatives")); context_provider_with_support->BindToCurrentThread(); CHECK( context_provider_with_support->GrContext()->supportsDistanceFieldText()); - Raster(context_provider_with_support, font_manager->strike_client(), data, - size); + Raster(context_provider_with_support, font_manager->strike_client(), + &paint_cache, data, size); font_manager->Unlock(locked_handles); font_manager->Destroy(); diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc index 0c56de338da..5802b3c369d 100644 --- a/chromium/cc/paint/paint_op_buffer_serializer.cc +++ b/chromium/cc/paint/paint_op_buffer_serializer.cc @@ -66,6 +66,7 @@ PaintOpBufferSerializer::PaintOpBufferSerializer( SerializeCallback serialize_cb, ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkStrikeServer* strike_server, SkColorSpace* color_space, bool can_use_lcd_text, @@ -75,6 +76,7 @@ PaintOpBufferSerializer::PaintOpBufferSerializer( : serialize_cb_(std::move(serialize_cb)), image_provider_(image_provider), transfer_cache_(transfer_cache), + paint_cache_(paint_cache), strike_server_(strike_server), color_space_(color_space), can_use_lcd_text_(can_use_lcd_text), @@ -385,8 +387,8 @@ void PaintOpBufferSerializer::RestoreToCount( PaintOp::SerializeOptions PaintOpBufferSerializer::MakeSerializeOptions() { return PaintOp::SerializeOptions( - image_provider_, transfer_cache_, canvas_, strike_server_, color_space_, - can_use_lcd_text_, context_supports_distance_field_text_, + image_provider_, transfer_cache_, paint_cache_, canvas_, strike_server_, + color_space_, can_use_lcd_text_, context_supports_distance_field_text_, max_texture_size_, max_texture_bytes_, canvas_->getTotalMatrix()); } @@ -395,6 +397,7 @@ SimpleBufferSerializer::SimpleBufferSerializer( size_t size, ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkStrikeServer* strike_server, SkColorSpace* color_space, bool can_use_lcd_text, @@ -406,6 +409,7 @@ SimpleBufferSerializer::SimpleBufferSerializer( base::Unretained(this)), image_provider, transfer_cache, + paint_cache, strike_server, color_space, can_use_lcd_text, diff --git a/chromium/cc/paint/paint_op_buffer_serializer.h b/chromium/cc/paint/paint_op_buffer_serializer.h index b12ba632d39..4dfd6c13c97 100644 --- a/chromium/cc/paint/paint_op_buffer_serializer.h +++ b/chromium/cc/paint/paint_op_buffer_serializer.h @@ -11,8 +11,9 @@ #include "ui/gfx/geometry/rect_f.h" namespace cc { - +class ClientPaintCache; class TransferCacheSerializeHelper; + class CC_PAINT_EXPORT PaintOpBufferSerializer { public: using SerializeCallback = @@ -21,6 +22,7 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer { PaintOpBufferSerializer(SerializeCallback serialize_cb, ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkStrikeServer* strike_server, SkColorSpace* color_space, bool can_use_lcd_text, @@ -102,6 +104,7 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer { SerializeCallback serialize_cb_; ImageProvider* image_provider_; TransferCacheSerializeHelper* transfer_cache_; + ClientPaintCache* paint_cache_; SkStrikeServer* strike_server_; SkColorSpace* color_space_; bool can_use_lcd_text_; @@ -122,6 +125,7 @@ class CC_PAINT_EXPORT SimpleBufferSerializer : public PaintOpBufferSerializer { size_t size, ImageProvider* image_provider, TransferCacheSerializeHelper* transfer_cache, + ClientPaintCache* paint_cache, SkStrikeServer* strike_server, SkColorSpace* color_space, bool can_use_lcd_text, diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc index 557a1187a17..8e007c409db 100644 --- a/chromium/cc/paint/paint_op_buffer_unittest.cc +++ b/chromium/cc/paint/paint_op_buffer_unittest.cc @@ -1160,10 +1160,9 @@ std::vector<std::vector<sk_sp<SkTypeface>>> test_typefaces = { }(), }; -std::vector<scoped_refptr<PaintTextBlob>> test_paint_blobs = { +std::vector<sk_sp<SkTextBlob>> test_paint_blobs = { [] { - SkPaint font; - font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkFont font; font.setTypeface(test_typefaces[0][0]); SkTextBlobBuilder builder; @@ -1172,12 +1171,10 @@ std::vector<scoped_refptr<PaintTextBlob>> test_paint_blobs = { builder.allocRun(font, glyph_count, 1.2f, 2.3f, &test_rects[0]); // allocRun() allocates only the glyph buffer. std::fill(run.glyphs, run.glyphs + glyph_count, 0); - return base::MakeRefCounted<PaintTextBlob>(builder.make(), - test_typefaces[0]); + return builder.make(); }(), [] { - SkPaint font; - font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkFont font; font.setTypeface(test_typefaces[1][0]); SkTextBlobBuilder builder; @@ -1202,8 +1199,7 @@ std::vector<scoped_refptr<PaintTextBlob>> test_paint_blobs = { // pos buffer. std::fill(run3.glyphs, run3.glyphs + glyph_count, 0); std::fill(run3.pos, run3.pos + glyph_count, 0); - return base::MakeRefCounted<PaintTextBlob>(builder.make(), - test_typefaces[1]); + return builder.make(); }(), }; @@ -1216,6 +1212,16 @@ std::vector<PaintImage> test_images = { CreateDiscardablePaintImage(gfx::Size(50, 50)), }; +std::vector<scoped_refptr<SkottieWrapper>> test_skotties = { + CreateSkottie(gfx::Size(10, 20), 4), CreateSkottie(gfx::Size(100, 40), 5), + CreateSkottie(gfx::Size(80, 70), 6)}; + +std::vector<float> test_skottie_floats = {0, 0.1f, 1.f}; + +std::vector<SkRect> test_skottie_rects = {SkRect::MakeXYWH(10, 20, 30, 40), + SkRect::MakeXYWH(0, 5, 10, 20), + SkRect::MakeXYWH(6, 0, 3, 50)}; + // Writes as many ops in |buffer| as can fit in |output_size| to |output|. // Records the numbers of bytes written for each op. class SimpleSerializer { @@ -1498,6 +1504,15 @@ void PushDrawRRectOps(PaintOpBuffer* buffer) { ValidateOps<DrawRRectOp>(buffer); } +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]); + } + ValidateOps<DrawSkottieOp>(buffer); +} + void PushDrawTextBlobOps(PaintOpBuffer* buffer) { size_t len = std::min(std::min(test_paint_blobs.size(), test_flags.size()), test_floats.size() - 1); @@ -1637,6 +1652,10 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { case PaintOpType::DrawRRect: PushDrawRRectOps(&buffer_); break; + case PaintOpType::DrawSkottie: + // Not supported + // TODO(malaykeshav): Add test when Drawable supports serialization. + break; case PaintOpType::DrawTextBlob: PushDrawTextBlobOps(&buffer_); break; @@ -1679,9 +1698,11 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { } bool IsTypeSupported() { - // 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; + // DrawRecordOps and DrawSkottieOps must be flattened and are not currently + // serialized. All other types must push non-zero amounts of ops in + // PushTestOps. + return GetParamType() != PaintOpType::DrawRecord && + GetParamType() != PaintOpType::DrawSkottie; } protected: @@ -1718,12 +1739,9 @@ TEST_P(PaintOpSerializationTest, SmokeTest) { PaintOpBuffer::Iterator iter(&buffer_); size_t i = 0; - PaintOp::DeserializeOptions deserialize_options( - serializer.options_provider()->transfer_cache_helper(), - serializer.options_provider()->strike_client()); - for (auto* base_written : - DeserializerIterator(output_.get(), serializer.TotalBytesWritten(), - deserialize_options)) { + for (auto* base_written : DeserializerIterator( + output_.get(), serializer.TotalBytesWritten(), + serializer.options_provider()->deserialize_options())) { SCOPED_TRACE(base::StringPrintf( "%s #%zu", PaintOpTypeToString(GetParamType()).c_str(), i)); ASSERT_EQ(!*iter, !base_written); @@ -1761,6 +1779,7 @@ TEST_P(PaintOpSerializationTest, SerializationFailures) { // Attempt to write op into a buffer of size |i|, and only expect // it to succeed if the buffer is large enough. for (size_t i = 0; i < bytes_written[op_idx] + 2; ++i) { + options_provider.ClearPaintCache(); size_t written_bytes = iter->Serialize( output_.get(), i, options_provider.serialize_options()); if (i >= expected_bytes) { @@ -1932,8 +1951,8 @@ TEST(PaintOpSerializationTest, CompleteBufferSerialization) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2012,8 +2031,8 @@ TEST(PaintOpSerializationTest, Preamble) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2115,8 +2134,8 @@ TEST(PaintOpSerializationTest, SerializesNestedRecords) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2192,8 +2211,8 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2258,8 +2277,8 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2660,6 +2679,19 @@ TEST(PaintOpBufferTest, BoundingRect_DrawDRRectOp) { } } +TEST(PaintOpBufferTest, BoundingRect_DrawSkottieOp) { + PaintOpBuffer buffer; + PushDrawSkottieOps(&buffer); + + SkRect rect; + for (auto* base_op : PaintOpBuffer::Iterator(&buffer)) { + auto* op = static_cast<DrawSkottieOp*>(base_op); + + ASSERT_TRUE(PaintOp::GetBounds(op, &rect)); + EXPECT_EQ(rect, op->dst.makeSorted()); + } +} + TEST(PaintOpBufferTest, BoundingRect_DrawTextBlobOp) { PaintOpBuffer buffer; PushDrawTextBlobOps(&buffer); @@ -2669,10 +2701,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawTextBlobOp) { auto* op = static_cast<DrawTextBlobOp*>(base_op); ASSERT_TRUE(PaintOp::GetBounds(op, &rect)); - EXPECT_EQ(rect, op->blob->ToSkTextBlob() - ->bounds() - .makeOffset(op->x, op->y) - .makeSorted()); + EXPECT_EQ(rect, op->blob->bounds().makeOffset(op->x, op->y).makeSorted()); } } @@ -2880,8 +2909,8 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -2999,11 +3028,8 @@ TEST_P(PaintFilterSerializationTest, Basic) { ASSERT_GT(writer.size(), 0u) << PaintFilter::TypeToString(filter->type()); sk_sp<PaintFilter> deserialized_filter; - PaintOp::DeserializeOptions deserialize_options( - options_provider.transfer_cache_helper(), - options_provider.strike_client()); - PaintOpReader reader(memory.data(), writer.size(), deserialize_options, - GetParam()); + PaintOpReader reader(memory.data(), writer.size(), + options_provider.deserialize_options(), GetParam()); reader.Read(&deserialized_filter); ASSERT_TRUE(deserialized_filter); EXPECT_TRUE(*filter == *deserialized_filter); @@ -3029,8 +3055,8 @@ TEST(PaintOpBufferTest, PaintRecordShaderSerialization) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3121,10 +3147,8 @@ TEST(PaintOpBufferTest, SecurityConstrainedImageSerialization) { writer.Write(filter.get()); sk_sp<PaintFilter> out_filter; - PaintOp::DeserializeOptions deserialize_options( - options_provider.transfer_cache_helper(), - options_provider.strike_client()); - PaintOpReader reader(memory.get(), writer.size(), deserialize_options, + PaintOpReader reader(memory.get(), writer.size(), + options_provider.deserialize_options(), enable_security_constraints); reader.Read(&out_filter); EXPECT_TRUE(*filter == *out_filter); @@ -3150,8 +3174,8 @@ TEST(PaintOpBufferTest, DrawImageRectSerializeScaledImages) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3187,8 +3211,8 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3227,8 +3251,8 @@ TEST(PaintOpBufferTest, RecordShadersCached) { SimpleBufferSerializer serializer( memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), transfer_cache, - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3253,8 +3277,8 @@ TEST(PaintOpBufferTest, RecordShadersCached) { SimpleBufferSerializer serializer( memory_scaled.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), transfer_cache, - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3266,7 +3290,8 @@ TEST(PaintOpBufferTest, RecordShadersCached) { sk_sp<PaintRecord> records[5]; const SkShader* last_shader = nullptr; PaintOp::DeserializeOptions deserialize_options( - transfer_cache, options_provider.strike_client()); + transfer_cache, options_provider.service_paint_cache(), + options_provider.strike_client()); // Several deserialization test cases: // (0) deserialize once, verify cached is the same as deserialized version @@ -3358,8 +3383,8 @@ TEST(PaintOpBufferTest, RecordShadersCachedSize) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); @@ -3367,7 +3392,8 @@ TEST(PaintOpBufferTest, RecordShadersCachedSize) { serializer.Serialize(buffer.get()); PaintOp::DeserializeOptions deserialize_options( - transfer_cache, options_provider.strike_client()); + transfer_cache, options_provider.service_paint_cache(), + options_provider.strike_client()); auto record = PaintOpBuffer::MakeFromMemory( memory.get(), serializer.written(), deserialize_options); auto* shader_entry = @@ -3409,8 +3435,8 @@ TEST(PaintOpBufferTest, NullImages) { memory.get(), PaintOpBuffer::kInitialBufferSize, options_provider.image_provider(), options_provider.transfer_cache_helper(), - options_provider.strike_server(), options_provider.color_space(), - options_provider.can_use_lcd_text(), + options_provider.client_paint_cache(), options_provider.strike_server(), + options_provider.color_space(), options_provider.can_use_lcd_text(), options_provider.context_supports_distance_field_text(), options_provider.max_texture_size(), options_provider.max_texture_bytes()); diff --git a/chromium/cc/paint/paint_op_helper_unittest.cc b/chromium/cc/paint/paint_op_helper_unittest.cc index d94f2541ff4..eac6e4ddc62 100644 --- a/chromium/cc/paint/paint_op_helper_unittest.cc +++ b/chromium/cc/paint/paint_op_helper_unittest.cc @@ -65,7 +65,7 @@ TEST(PaintOpHelper, DrawDRRectToString) { str, "DrawDRRectOp(outer=[bounded by 1.000,2.000 3.000x4.000], inner=[bounded " "by 5.000,6.000 7.000x8.000], flags=[color=rgba(0, 0, 0, 255), " - "blendMode=kSrcOver, isAntiAlias=false, isVerticalText=false, " + "blendMode=kSrcOver, isAntiAlias=false, " "isSubpixelText=false, isLCDRenderText=false, hinting=kNormal_Hinting, " "isAutohinted=false, isDither=false, textEncoding=kUTF8_TextEncoding, " "textSize=12.000, filterQuality=kNone_SkFilterQuality, " @@ -84,7 +84,7 @@ TEST(PaintOpHelper, DrawImageToString) { str, "DrawImageOp(image=<paint image>, left=10.500, top=20.300, " "flags=[color=rgba(0, 0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -105,7 +105,7 @@ TEST(PaintOpHelper, DrawImageRectToString) { "DrawImageRectOp(image=<paint image>, src=[1.000,2.000 3.000x4.000], " "dst=[5.000,6.000 7.000x8.000], constraint=kStrict_SrcRectConstraint, " "flags=[color=rgba(0, 0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -121,7 +121,7 @@ TEST(PaintOpHelper, DrawIRectToString) { std::string str = PaintOpHelper::ToString(&op); EXPECT_EQ(str, "DrawIRectOp(rect=[1,2 3x4], flags=[color=rgba(0, 0, 0, 255), " - "blendMode=kSrcOver, isAntiAlias=false, isVerticalText=false, " + "blendMode=kSrcOver, isAntiAlias=false, " "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " @@ -141,7 +141,7 @@ TEST(PaintOpHelper, DrawLineToString) { str, "DrawLineOp(x0=1.100, y0=2.200, x1=3.300, y1=4.400, flags=[color=rgba(0, " "0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -159,7 +159,7 @@ TEST(PaintOpHelper, DrawOvalToString) { str, "DrawOvalOp(oval=[100.000,200.000 300.000x400.000], flags=[color=rgba(0, " "0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -176,7 +176,7 @@ TEST(PaintOpHelper, DrawPathToString) { std::string str = PaintOpHelper::ToString(&op); EXPECT_EQ(str, "DrawPathOp(path=<SkPath>, flags=[color=rgba(0, 0, 0, 255), " - "blendMode=kSrcOver, isAntiAlias=false, isVerticalText=false, " + "blendMode=kSrcOver, isAntiAlias=false, " "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " @@ -201,7 +201,7 @@ TEST(PaintOpHelper, DrawRectToString) { EXPECT_EQ( str, "DrawRectOp(rect=[-1.000,-2.000 -3.000x-4.000], flags=[color=rgba(0, 0, " - "0, 255), blendMode=kSrcOver, isAntiAlias=false, isVerticalText=false, " + "0, 255), blendMode=kSrcOver, isAntiAlias=false, " "isSubpixelText=false, isLCDRenderText=false, hinting=kNormal_Hinting, " "isAutohinted=false, isDither=false, textEncoding=kUTF8_TextEncoding, " "textSize=12.000, filterQuality=kNone_SkFilterQuality, " @@ -221,7 +221,7 @@ TEST(PaintOpHelper, DrawRRectToString) { str, "DrawRRectOp(rrect=[bounded by -1.000,-2.000 3.000x4.000], " "flags=[color=rgba(0, 0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -239,7 +239,7 @@ TEST(PaintOpHelper, DrawTextBlobToString) { str, "DrawTextBlobOp(blob=(nil), x=100.000, y=-222.000, flags=[color=rgba(0, " "0, 0, 255), blendMode=kSrcOver, isAntiAlias=false, " - "isVerticalText=false, isSubpixelText=false, isLCDRenderText=false, " + "isSubpixelText=false, isLCDRenderText=false, " "hinting=kNormal_Hinting, isAutohinted=false, isDither=false, " "textEncoding=kUTF8_TextEncoding, textSize=12.000, " "filterQuality=kNone_SkFilterQuality, strokeWidth=0.000, " @@ -281,7 +281,7 @@ TEST(PaintOpHelper, SaveLayerToString) { EXPECT_EQ( str, "SaveLayerOp(bounds=[1.000,2.000 3.000x4.000], flags=[color=rgba(0, 0, " - "0, 255), blendMode=kSrcOver, isAntiAlias=false, isVerticalText=false, " + "0, 255), blendMode=kSrcOver, isAntiAlias=false, " "isSubpixelText=false, isLCDRenderText=false, hinting=kNormal_Hinting, " "isAutohinted=false, isDither=false, textEncoding=kUTF8_TextEncoding, " "textSize=12.000, filterQuality=kNone_SkFilterQuality, " diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc index 2f9220f2ae1..8a4e78df588 100644 --- a/chromium/cc/paint/paint_op_perftest.cc +++ b/chromium/cc/paint/paint_op_perftest.cc @@ -51,6 +51,7 @@ class PaintOpPerfTest : public testing::Test { serialized_data_.get(), kMaxSerializedBufferBytes, test_options_provider.image_provider(), test_options_provider.transfer_cache_helper(), + test_options_provider.client_paint_cache(), test_options_provider.strike_server(), test_options_provider.color_space(), test_options_provider.can_use_lcd_text(), @@ -59,6 +60,9 @@ class PaintOpPerfTest : public testing::Test { test_options_provider.max_texture_bytes()); serializer.Serialize(&buffer, nullptr, preamble); bytes_written = serializer.written(); + + // Force client paint cache entries to be written every time. + test_options_provider.client_paint_cache()->PurgeAll(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); CHECK_GT(bytes_written, 0u); @@ -80,6 +84,7 @@ class PaintOpPerfTest : public testing::Test { to_read, remaining_read_bytes, deserialized_data_.get(), sizeof(LargestPaintOp), &bytes_read, test_options_provider.deserialize_options()); + CHECK(deserialized_op); deserialized_op->DestroyThis(); DCHECK_GE(remaining_read_bytes, bytes_read); @@ -159,8 +164,7 @@ TEST_F(PaintOpPerfTest, TextOps) { auto typeface = SkTypeface::MakeDefault(); - SkPaint font; - font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkFont font; font.setTypeface(typeface); SkTextBlobBuilder builder; @@ -168,8 +172,7 @@ TEST_F(PaintOpPerfTest, TextOps) { SkRect rect = SkRect::MakeXYWH(1, 1, 1, 1); const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f, &rect); std::fill(run.glyphs, run.glyphs + glyph_count, 0); - std::vector<sk_sp<SkTypeface>> typefaces = {typeface}; - auto blob = base::MakeRefCounted<PaintTextBlob>(builder.make(), typefaces); + auto blob = builder.make(); PaintFlags flags; for (size_t i = 0; i < 100; ++i) diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc index f5a344fd349..9805e9c8149 100644 --- a/chromium/cc/paint/paint_op_reader.cc +++ b/chromium/cc/paint/paint_op_reader.cc @@ -7,13 +7,15 @@ #include <stddef.h> #include <algorithm> +#include "base/bits.h" +#include "base/debug/dump_without_crashing.h" #include "base/stl_util.h" #include "cc/paint/image_transfer_cache_entry.h" +#include "cc/paint/paint_cache.h" #include "cc/paint/paint_flags.h" #include "cc/paint/paint_image_builder.h" #include "cc/paint/paint_op_buffer.h" #include "cc/paint/paint_shader.h" -#include "cc/paint/path_transfer_cache_entry.h" #include "cc/paint/shader_transfer_cache_entry.h" #include "cc/paint/transfer_cache_deserialize_helper.h" #include "third_party/skia/include/core/SkPath.h" @@ -100,7 +102,12 @@ template <typename T> void PaintOpReader::ReadSimple(T* val) { static_assert(base::is_trivially_copyable<T>::value, "Not trivially copyable"); - if (remaining_bytes_ < sizeof(T)) + + // Align everything to 4 bytes, as the writer does. + static constexpr size_t kAlign = 4; + size_t size = base::bits::Align(sizeof(T), kAlign); + + if (remaining_bytes_ < size) SetInvalid(); if (!valid_) return; @@ -111,8 +118,8 @@ void PaintOpReader::ReadSimple(T* val) { // use assignment. *val = *reinterpret_cast<const T*>(const_cast<const char*>(memory_)); - memory_ += sizeof(T); - remaining_bytes_ -= sizeof(T); + memory_ += size; + remaining_bytes_ -= size; } template <typename T> @@ -194,18 +201,38 @@ void PaintOpReader::Read(SkRRect* rect) { } void PaintOpReader::Read(SkPath* path) { - uint32_t transfer_cache_entry_id; - ReadSimple(&transfer_cache_entry_id); + uint32_t path_id; + ReadSimple(&path_id); if (!valid_) return; - auto* entry = - options_.transfer_cache->GetEntryAs<ServicePathTransferCacheEntry>( - transfer_cache_entry_id); - if (entry) { - *path = entry->path(); - } else { - valid_ = false; + + size_t path_bytes = 0u; + ReadSize(&path_bytes); + if (path_bytes > remaining_bytes_) + SetInvalid(); + if (!valid_) + return; + + if (path_bytes != 0u) { + size_t bytes_read = + path->readFromMemory(const_cast<const char*>(memory_), path_bytes); + if (bytes_read == 0u) { + SetInvalid(); + return; + } + + options_.paint_cache->PutPath(path_id, *path); + memory_ += path_bytes; + remaining_bytes_ -= path_bytes; + return; } + + auto* cached_path = options_.paint_cache->GetPath(path_id); + if (!cached_path) { + SetInvalid(); + return; + } + *path = *cached_path; } void PaintOpReader::Read(PaintFlags* flags) { @@ -374,28 +401,45 @@ void PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) { remaining_bytes_ -= size; } -void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) { +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 || data_bytes == 0u) + if (remaining_bytes_ < data_bytes) SetInvalid(); if (!valid_) return; + if (data_bytes == 0u) { + auto cached_blob = options_.paint_cache->GetTextBlob(blob_id); + if (!cached_blob) { + SetInvalid(); + 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; - sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize( + sk_sp<SkTextBlob> deserialized_blob = SkTextBlob::Deserialize( const_cast<const char*>(memory_), data_bytes, procs); - if (!blob || typeface_ctx.invalid_typeface) { + if (!deserialized_blob || typeface_ctx.invalid_typeface) { SetInvalid(); return; } + options_.paint_cache->PutTextBlob(blob_id, deserialized_blob); - *paint_blob = base::MakeRefCounted<PaintTextBlob>( - std::move(blob), std::vector<sk_sp<SkTypeface>>()); + *blob = std::move(deserialized_blob); memory_ += data_bytes; remaining_bytes_ -= data_bytes; } @@ -570,6 +614,10 @@ void PaintOpReader::AlignMemory(size_t alignment) { } inline void PaintOpReader::SetInvalid() { + if (valid_ && options_.crash_dump_on_failure) { + // TODO(enne): make this DumpWithoutCrashing after http://crbug.com/910772 + // base::debug::DumpWithoutCrashing(); + } valid_ = false; } diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h index 0188c8d54da..6a9c8de4193 100644 --- a/chromium/cc/paint/paint_op_reader.h +++ b/chromium/cc/paint/paint_op_reader.h @@ -60,7 +60,7 @@ class CC_PAINT_EXPORT PaintOpReader { void Read(PaintFlags* flags); void Read(PaintImage* image); void Read(sk_sp<SkData>* data); - void Read(scoped_refptr<PaintTextBlob>* blob); + void Read(sk_sp<SkTextBlob>* blob); void Read(sk_sp<PaintFilter>* filter); void Read(sk_sp<PaintShader>* shader); void Read(SkMatrix* matrix); diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc index ceaf05e6cdb..f933da967e4 100644 --- a/chromium/cc/paint/paint_op_writer.cc +++ b/chromium/cc/paint/paint_op_writer.cc @@ -4,13 +4,14 @@ #include "cc/paint/paint_op_writer.h" +#include "base/bits.h" #include "cc/paint/draw_image.h" #include "cc/paint/image_provider.h" #include "cc/paint/image_transfer_cache_entry.h" +#include "cc/paint/paint_cache.h" #include "cc/paint/paint_flags.h" #include "cc/paint/paint_op_buffer_serializer.h" #include "cc/paint/paint_shader.h" -#include "cc/paint/path_transfer_cache_entry.h" #include "cc/paint/transfer_cache_serialize_helper.h" #include "third_party/skia/include/core/SkSerialProcs.h" #include "third_party/skia/include/core/SkTextBlob.h" @@ -92,30 +93,31 @@ PaintOpWriter::~PaintOpWriter() = default; template <typename T> void PaintOpWriter::WriteSimple(const T& val) { static_assert(base::is_trivially_copyable<T>::value, ""); - EnsureBytes(sizeof(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::Align(sizeof(T), kAlign); + EnsureBytes(size); if (!valid_) return; reinterpret_cast<T*>(memory_)[0] = val; - memory_ += sizeof(T); - remaining_bytes_ -= sizeof(T); + memory_ += size; + remaining_bytes_ -= size; } - void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) { - AlignMemory(8); if (!val) { WriteSize(static_cast<size_t>(0u)); return; } - size_t size_offset = sizeof(uint64_t); - EnsureBytes(size_offset); + uint64_t* size_memory = WriteSize(0u); if (!valid_) return; - char* size_memory = memory_; - memory_ += size_offset; - remaining_bytes_ -= size_offset; size_t bytes_written = val->serialize( memory_, RoundDownToAlignment(remaining_bytes_, kSkiaAlignment)); @@ -123,14 +125,16 @@ void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) { valid_ = false; return; } - reinterpret_cast<uint64_t*>(size_memory)[0] = bytes_written; + *size_memory = bytes_written; memory_ += bytes_written; remaining_bytes_ -= bytes_written; } -void PaintOpWriter::WriteSize(size_t size) { +uint64_t* PaintOpWriter::WriteSize(size_t size) { AlignMemory(8); + uint64_t* memory = reinterpret_cast<uint64_t*>(memory_); WriteSimple<uint64_t>(size); + return memory; } void PaintOpWriter::Write(SkScalar data) { @@ -167,13 +171,26 @@ void PaintOpWriter::Write(const SkRRect& rect) { void PaintOpWriter::Write(const SkPath& path) { auto id = path.getGenerationID(); - auto locked = - options_.transfer_cache->LockEntry(TransferCacheEntryType::kPath, id); - if (!locked) { - options_.transfer_cache->CreateEntry(ClientPathTransferCacheEntry(path)); - options_.transfer_cache->AssertLocked(TransferCacheEntryType::kPath, id); - } Write(id); + + uint64_t* bytes_to_skip = WriteSize(0u); + if (!valid_) + return; + + if (options_.paint_cache->Get(PaintCacheDataType::kPath, id)) + return; + uint64_t bytes_required = path.writeToMemory(nullptr); + if (bytes_required > remaining_bytes_) { + valid_ = false; + return; + } + + size_t bytes_written = path.writeToMemory(memory_); + DCHECK_EQ(bytes_written, bytes_required); + options_.paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written); + *bytes_to_skip = bytes_written; + memory_ += bytes_written; + remaining_bytes_ -= bytes_written; } void PaintOpWriter::Write(const PaintFlags& flags) { @@ -289,22 +306,20 @@ void PaintOpWriter::Write(const SkColorSpace* color_space) { remaining_bytes_ -= written; } -void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& paint_blob) { - DCHECK(paint_blob); +void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) { + DCHECK(blob); if (!valid_) return; - AlignMemory(8); - - const auto& blob = paint_blob->ToSkTextBlob(); - size_t size_offset = sizeof(uint64_t); - EnsureBytes(size_offset); + AlignMemory(4); + uint32_t blob_id = blob->uniqueID(); + Write(blob_id); + uint64_t* size_memory = WriteSize(0u); if (!valid_) return; - char* size_memory = memory_; - memory_ += size_offset; - remaining_bytes_ -= size_offset; + 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); @@ -320,7 +335,10 @@ void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& paint_blob) { valid_ = false; return; } - reinterpret_cast<uint64_t*>(size_memory)[0] = bytes_written; + + options_.paint_cache->Put(PaintCacheDataType::kTextBlob, blob_id, + bytes_written); + *size_memory = bytes_written; memory_ += bytes_written; remaining_bytes_ -= bytes_written; } @@ -342,9 +360,8 @@ sk_sp<PaintShader> PaintOpWriter::TransformShaderIfNecessary( &quality, paint_image_needs_mips); } - if (type == PaintShader::Type::kPaintRecord) { + if (type == PaintShader::Type::kPaintRecord) return original->CreateScaledPaintRecord(ctm, paint_record_post_scale); - } return sk_ref_sp<PaintShader>(original); } @@ -484,7 +501,7 @@ void PaintOpWriter::Write(const PaintFilter* filter) { if (!valid_) return; - AlignMemory(4); + AlignMemory(kSkiaAlignment); switch (filter->type()) { case PaintFilter::Type::kNullFilter: NOTREACHED(); @@ -748,16 +765,12 @@ void PaintOpWriter::Write(const PaintRecord* record, if (!valid_) return; - char* size_memory = memory_; - - memory_ += size_offset; - remaining_bytes_ -= size_offset; + uint64_t* size_memory = WriteSize(0u); if (!valid_) return; if (enable_security_constraints_) { // We don't serialize PaintRecords when security constraints are enabled. - reinterpret_cast<size_t*>(size_memory)[0] = 0u; return; } @@ -767,9 +780,10 @@ void PaintOpWriter::Write(const PaintRecord* record, const bool can_use_lcd_text = false; SimpleBufferSerializer serializer( memory_, remaining_bytes_, options_.image_provider, - options_.transfer_cache, options_.strike_server, options_.color_space, - can_use_lcd_text, options_.context_supports_distance_field_text, - options_.max_texture_size, options_.max_texture_bytes); + options_.transfer_cache, options_.paint_cache, options_.strike_server, + options_.color_space, can_use_lcd_text, + options_.context_supports_distance_field_text, options_.max_texture_size, + options_.max_texture_bytes); serializer.Serialize(record, playback_rect, post_scale, post_matrix_for_analysis); @@ -784,7 +798,7 @@ void PaintOpWriter::Write(const PaintRecord* record, // Write the size to the size memory, which preceeds the memory for the // record. - reinterpret_cast<uint64_t*>(size_memory)[0] = serializer.written(); + *size_memory = serializer.written(); // 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. diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h index 87071bbd8e7..2b7121c181b 100644 --- a/chromium/cc/paint/paint_op_writer.h +++ b/chromium/cc/paint/paint_op_writer.h @@ -42,7 +42,7 @@ class CC_PAINT_EXPORT PaintOpWriter { size_t size() const { return valid_ ? size_ - remaining_bytes_ : 0u; } - void WriteSize(size_t size); + uint64_t* WriteSize(size_t size); void Write(SkScalar data); void Write(SkMatrix data); @@ -60,7 +60,7 @@ class CC_PAINT_EXPORT PaintOpWriter { void Write(const SkColorSpace* data); void Write(const PaintShader* shader, SkFilterQuality quality); void Write(const PaintFilter* filter); - void Write(const scoped_refptr<PaintTextBlob>& blob); + void Write(const sk_sp<SkTextBlob>& blob); void Write(SkColorType color_type); void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); } diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc index c9b0c8d38d7..9c5ce1c746b 100644 --- a/chromium/cc/paint/paint_shader.cc +++ b/chromium/cc/paint/paint_shader.cc @@ -52,6 +52,13 @@ bool CompareMatrices(const SkMatrix& a, const PaintShader::RecordShaderId PaintShader::kInvalidRecordShaderId = -1; +sk_sp<PaintShader> PaintShader::MakeEmpty() { + sk_sp<PaintShader> shader(new PaintShader(Type::kEmpty)); + + shader->CreateSkShader(); + return shader; +} + sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) { sk_sp<PaintShader> shader(new PaintShader(Type::kColor)); @@ -214,7 +221,7 @@ PaintShader::PaintShader(Type type) : shader_type_(type) {} PaintShader::~PaintShader() = default; bool PaintShader::has_discardable_images() const { - return (image_ && image_.IsLazyGenerated()) || + return (image_ && !image_.IsTextureBacked()) || (record_ && record_->HasDiscardableImages()); } @@ -269,6 +276,12 @@ sk_sp<PaintShader> PaintShader::CreateScaledPaintRecord( gfx::SizeF* raster_scale) const { DCHECK_EQ(shader_type_, Type::kPaintRecord); + // If this is already fixed scale, then this is already good to go. + if (scaling_behavior_ == ScalingBehavior::kFixedScale) { + *raster_scale = gfx::SizeF(1.f, 1.f); + return sk_ref_sp<PaintShader>(this); + } + // For creating a decoded PaintRecord shader, we need to do the following: // 1) Figure out the scale at which the record should be rasterization given // the ctm and local_matrix on the shader. @@ -367,6 +380,9 @@ void PaintShader::CreateSkShader(const gfx::SizeF* raster_scale, DCHECK(!cached_shader_); switch (shader_type_) { + case Type::kEmpty: + cached_shader_ = SkShader::MakeEmptyShader(); + break; case Type::kColor: // This will be handled by the fallback check below. break; @@ -481,6 +497,7 @@ bool PaintShader::IsValid() const { return true; switch (shader_type_) { + case Type::kEmpty: case Type::kColor: return true; case Type::kSweepGradient: @@ -539,6 +556,7 @@ bool PaintShader::operator==(const PaintShader& other) const { // Variables that only some shaders use. switch (shader_type_) { + case Type::kEmpty: case Type::kColor: break; case Type::kSweepGradient: diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h index b0444bbfd96..17cbd1f88b8 100644 --- a/chromium/cc/paint/paint_shader.h +++ b/chromium/cc/paint/paint_shader.h @@ -27,6 +27,7 @@ using PaintRecord = PaintOpBuffer; class CC_PAINT_EXPORT PaintShader : public SkRefCnt { public: enum class Type : uint8_t { + kEmpty, kColor, kLinearGradient, kRadialGradient, @@ -45,6 +46,8 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt { // shader that is backed by the paint record. enum class ScalingBehavior : uint8_t { kRasterAtScale, kFixedScale }; + static sk_sp<PaintShader> MakeEmpty(); + static sk_sp<PaintShader> MakeColor(SkColor color); static sk_sp<PaintShader> MakeLinearGradient( diff --git a/chromium/cc/paint/paint_text_blob.cc b/chromium/cc/paint/paint_text_blob.cc deleted file mode 100644 index d82d1b7b927..00000000000 --- a/chromium/cc/paint/paint_text_blob.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/paint/paint_text_blob.h" - -#include <vector> - -#include "third_party/skia/include/core/SkTextBlob.h" - -namespace cc { - -PaintTextBlob::PaintTextBlob() = default; -PaintTextBlob::PaintTextBlob(sk_sp<SkTextBlob> blob, - std::vector<sk_sp<SkTypeface>> typefaces) - : sk_blob_(std::move(blob)), typefaces_(std::move(typefaces)) {} -PaintTextBlob::~PaintTextBlob() = default; - -} // namespace cc diff --git a/chromium/cc/paint/paint_text_blob.h b/chromium/cc/paint/paint_text_blob.h deleted file mode 100644 index cbe9ed1ba64..00000000000 --- a/chromium/cc/paint/paint_text_blob.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_PAINT_PAINT_TEXT_BLOB_H_ -#define CC_PAINT_PAINT_TEXT_BLOB_H_ - -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "cc/paint/paint_export.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/include/core/SkTextBlob.h" -#include "third_party/skia/include/core/SkTypeface.h" - -namespace cc { - -class CC_PAINT_EXPORT PaintTextBlob - : public base::RefCountedThreadSafe<PaintTextBlob> { - public: - PaintTextBlob(); - PaintTextBlob(sk_sp<SkTextBlob> blob, - std::vector<sk_sp<SkTypeface>> typefaces); - - const sk_sp<SkTextBlob>& ToSkTextBlob() const { return sk_blob_; } - const std::vector<sk_sp<SkTypeface>>& typefaces() const { return typefaces_; } - - operator bool() const { return !!sk_blob_; } - - private: - friend base::RefCountedThreadSafe<PaintTextBlob>; - - ~PaintTextBlob(); - - sk_sp<SkTextBlob> sk_blob_; - std::vector<sk_sp<SkTypeface>> typefaces_; - - DISALLOW_COPY_AND_ASSIGN(PaintTextBlob); -}; - -} // namespace cc - -#endif // CC_PAINT_PAINT_TEXT_BLOB_H_ diff --git a/chromium/cc/paint/paint_text_blob_builder.cc b/chromium/cc/paint/paint_text_blob_builder.cc deleted file mode 100644 index 2f4550a06be..00000000000 --- a/chromium/cc/paint/paint_text_blob_builder.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/paint/paint_text_blob_builder.h" - -namespace cc { - -PaintTextBlobBuilder::PaintTextBlobBuilder() = default; -PaintTextBlobBuilder::~PaintTextBlobBuilder() = default; - -scoped_refptr<PaintTextBlob> PaintTextBlobBuilder::TakeTextBlob() { - auto result = base::MakeRefCounted<PaintTextBlob>(sk_builder_.make(), - std::move(typefaces_)); - typefaces_.clear(); - return result; -} - -const PaintTextBlobBuilder::RunBuffer& PaintTextBlobBuilder::AllocRunPosH( - const PaintFont& font, - int count, - SkScalar y, - const SkRect* bounds) { - typefaces_.push_back(font.typeface()); - return sk_builder_.allocRunPosH(font.ToSkPaint(), count, y, bounds); -} - -const PaintTextBlobBuilder::RunBuffer& PaintTextBlobBuilder::AllocRunPos( - const PaintFont& font, - int count, - const SkRect* bounds) { - typefaces_.push_back(font.typeface()); - return sk_builder_.allocRunPos(font.ToSkPaint(), count, bounds); -} - -} // namespace cc diff --git a/chromium/cc/paint/paint_text_blob_builder.h b/chromium/cc/paint/paint_text_blob_builder.h deleted file mode 100644 index 8c87f9b5cfa..00000000000 --- a/chromium/cc/paint/paint_text_blob_builder.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_ -#define CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_ - -#include <vector> - -#include "base/macros.h" -#include "cc/paint/paint_export.h" -#include "cc/paint/paint_font.h" -#include "cc/paint/paint_text_blob.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkScalar.h" -#include "third_party/skia/include/core/SkTextBlob.h" - -namespace cc { - -class CC_PAINT_EXPORT PaintTextBlobBuilder { - public: - using RunBuffer = SkTextBlobBuilder::RunBuffer; - - PaintTextBlobBuilder(); - ~PaintTextBlobBuilder(); - - scoped_refptr<PaintTextBlob> TakeTextBlob(); - - // These functions pass the calls through to SkTextBlobBuilder, see its - // interface for details. - const RunBuffer& AllocRunPosH(const PaintFont& font, - int count, - SkScalar y, - const SkRect* bounds = nullptr); - - const RunBuffer& AllocRunPos(const PaintFont& font, - int count, - const SkRect* bounds = nullptr); - - private: - std::vector<sk_sp<SkTypeface>> typefaces_; - SkTextBlobBuilder sk_builder_; - - DISALLOW_COPY_AND_ASSIGN(PaintTextBlobBuilder); -}; - -} // namespace cc - -#endif // CC_PAINT_PAINT_TEXT_BLOB_BUILDER_H_ diff --git a/chromium/cc/paint/path_transfer_cache_entry.cc b/chromium/cc/paint/path_transfer_cache_entry.cc deleted file mode 100644 index c1490109c05..00000000000 --- a/chromium/cc/paint/path_transfer_cache_entry.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/paint/path_transfer_cache_entry.h" - -namespace cc { - -ClientPathTransferCacheEntry::ClientPathTransferCacheEntry(const SkPath& path) - : path_(path) { - size_ = path_.writeToMemory(nullptr); -} - -ClientPathTransferCacheEntry::~ClientPathTransferCacheEntry() = default; - -uint32_t ClientPathTransferCacheEntry::Id() const { - return path_.getGenerationID(); -} - -size_t ClientPathTransferCacheEntry::SerializedSize() const { - return size_; -} - -bool ClientPathTransferCacheEntry::Serialize(base::span<uint8_t> data) const { - DCHECK_EQ(data.size(), size_); - - size_t bytes_written = path_.writeToMemory(data.data()); - CHECK_LE(bytes_written, size_); - return true; -} - -ServicePathTransferCacheEntry::ServicePathTransferCacheEntry() = default; - -ServicePathTransferCacheEntry::~ServicePathTransferCacheEntry() = default; - -size_t ServicePathTransferCacheEntry::CachedSize() const { - return size_; -} - -bool ServicePathTransferCacheEntry::Deserialize( - GrContext* context, - base::span<const uint8_t> data) { - size_t read_bytes = path_.readFromMemory(data.data(), data.size()); - // Invalid path. - if (read_bytes == 0) - return false; - if (read_bytes > data.size()) - return false; - size_ = read_bytes; - - return true; -} - -} // namespace cc diff --git a/chromium/cc/paint/path_transfer_cache_entry.h b/chromium/cc/paint/path_transfer_cache_entry.h deleted file mode 100644 index b1282e3c11f..00000000000 --- a/chromium/cc/paint/path_transfer_cache_entry.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_ -#define CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_ - -#include "base/containers/span.h" -#include "cc/paint/paint_export.h" -#include "cc/paint/transfer_cache_entry.h" -#include "third_party/skia/include/core/SkPath.h" - -namespace cc { - -class CC_PAINT_EXPORT ClientPathTransferCacheEntry - : public ClientTransferCacheEntryBase<TransferCacheEntryType::kPath> { - public: - explicit ClientPathTransferCacheEntry(const SkPath& path); - ~ClientPathTransferCacheEntry() final; - uint32_t Id() const final; - size_t SerializedSize() const final; - bool Serialize(base::span<uint8_t> data) const final; - - private: - SkPath path_; - size_t size_ = 0u; -}; - -class CC_PAINT_EXPORT ServicePathTransferCacheEntry - : public ServiceTransferCacheEntryBase<TransferCacheEntryType::kPath> { - public: - ServicePathTransferCacheEntry(); - ~ServicePathTransferCacheEntry() final; - size_t CachedSize() const final; - bool Deserialize(GrContext* context, base::span<const uint8_t> data) final; - - const SkPath& path() const { return path_; } - - private: - SkPath path_; - size_t size_ = 0; -}; - -} // namespace cc - -#endif // CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_ diff --git a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc index 2c41fabd9d9..aa6fb645733 100644 --- a/chromium/cc/paint/raw_memory_transfer_cache_entry.cc +++ b/chromium/cc/paint/raw_memory_transfer_cache_entry.cc @@ -27,10 +27,10 @@ uint32_t ClientRawMemoryTransferCacheEntry::Id() const { bool ClientRawMemoryTransferCacheEntry::Serialize( base::span<uint8_t> data) const { - if (data.size() != data_.size()) + if (data.size() < data_.size()) return false; - memcpy(data.data(), data_.data(), data.size()); + memcpy(data.data(), data_.data(), data_.size()); return true; } diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc index 2250b26e803..2d9b4e4eb40 100644 --- a/chromium/cc/paint/record_paint_canvas.cc +++ b/chromium/cc/paint/record_paint_canvas.cc @@ -8,6 +8,7 @@ #include "cc/paint/paint_image_builder.h" #include "cc/paint/paint_record.h" #include "cc/paint/paint_recorder.h" +#include "cc/paint/skottie_wrapper.h" #include "third_party/skia/include/core/SkAnnotation.h" #include "third_party/skia/include/core/SkMetaData.h" #include "third_party/skia/include/utils/SkNWayCanvas.h" @@ -263,7 +264,13 @@ void RecordPaintCanvas::drawImageRect(const PaintImage& image, list_->push<DrawImageRectOp>(image, src, dst, flags, constraint); } -void RecordPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob, +void RecordPaintCanvas::drawSkottie(scoped_refptr<SkottieWrapper> skottie, + const SkRect& dst, + float t) { + list_->push<DrawSkottieOp>(std::move(skottie), dst, t); +} + +void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) { @@ -308,7 +315,7 @@ SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() { return &*canvas_; // Size the canvas to be large enough to contain the |recording_bounds|, which - // may not be positioned at th origin. + // may not be positioned at the origin. SkIRect enclosing_rect = recording_bounds_.roundOut(); canvas_.emplace(enclosing_rect.right(), enclosing_rect.bottom()); diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h index fb39721603f..cfa24116f45 100644 --- a/chromium/cc/paint/record_paint_canvas.h +++ b/chromium/cc/paint/record_paint_canvas.h @@ -15,7 +15,6 @@ #include "cc/paint/paint_canvas.h" #include "cc/paint/paint_flags.h" #include "cc/paint/paint_record.h" -#include "cc/paint/paint_text_blob.h" #include "third_party/skia/include/utils/SkNoDrawCanvas.h" namespace cc { @@ -84,8 +83,10 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas { const SkRect& dst, const PaintFlags* flags, SrcRectConstraint constraint) override; - - void drawTextBlob(scoped_refptr<PaintTextBlob> blob, + void drawSkottie(scoped_refptr<SkottieWrapper> skottie, + const SkRect& dst, + float t) override; + void drawTextBlob(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) override; diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc index ea360c2b630..4bb07e76333 100644 --- a/chromium/cc/paint/skia_paint_canvas.cc +++ b/chromium/cc/paint/skia_paint_canvas.cc @@ -303,7 +303,13 @@ void SkiaPaintCanvas::drawImageRect(const PaintImage& image, FlushAfterDrawIfNeeded(); } -void SkiaPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob, +void SkiaPaintCanvas::drawSkottie(scoped_refptr<SkottieWrapper> skottie, + const SkRect& dst, + float t) { + skottie->Draw(canvas_, t, dst); +} + +void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) { @@ -312,7 +318,7 @@ void SkiaPaintCanvas::drawTextBlob(scoped_refptr<PaintTextBlob> blob, if (!raster_flags.flags()) return; SkPaint paint = raster_flags.flags()->ToSkPaint(); - canvas_->drawTextBlob(blob->ToSkTextBlob(), x, y, paint); + canvas_->drawTextBlob(blob, x, y, paint); FlushAfterDrawIfNeeded(); } diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h index c514017abd1..458bf99d4da 100644 --- a/chromium/cc/paint/skia_paint_canvas.h +++ b/chromium/cc/paint/skia_paint_canvas.h @@ -14,7 +14,6 @@ #include "cc/paint/paint_canvas.h" #include "cc/paint/paint_flags.h" #include "cc/paint/paint_record.h" -#include "cc/paint/paint_text_blob.h" #include "third_party/skia/include/core/SkCanvas.h" namespace cc { @@ -107,8 +106,10 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas { const SkRect& dst, const PaintFlags* flags, SrcRectConstraint constraint) override; - - void drawTextBlob(scoped_refptr<PaintTextBlob> blob, + void drawSkottie(scoped_refptr<SkottieWrapper> skottie, + const SkRect& dst, + float t) override; + void drawTextBlob(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const PaintFlags& flags) override; diff --git a/chromium/cc/paint/skia_paint_image_generator.cc b/chromium/cc/paint/skia_paint_image_generator.cc index fc42d24b40f..3eb864f12cf 100644 --- a/chromium/cc/paint/skia_paint_image_generator.cc +++ b/chromium/cc/paint/skia_paint_image_generator.cc @@ -31,15 +31,19 @@ bool SkiaPaintImageGenerator::onGetPixels(const SkImageInfo& info, info, pixels, row_bytes, frame_index_, client_id_, uniqueID()); } -bool SkiaPaintImageGenerator::onQueryYUV8(SkYUVSizeInfo* size_info, - SkYUVColorSpace* color_space) const { - return paint_image_generator_->QueryYUV8(size_info, color_space); +bool SkiaPaintImageGenerator::onQueryYUVA8( + SkYUVASizeInfo* size_info, + SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + SkYUVColorSpace* color_space) const { + return paint_image_generator_->QueryYUVA8(size_info, indices, color_space); } -bool SkiaPaintImageGenerator::onGetYUV8Planes(const SkYUVSizeInfo& size_info, - void* planes[3]) { - return paint_image_generator_->GetYUV8Planes(size_info, planes, frame_index_, - uniqueID()); +bool SkiaPaintImageGenerator::onGetYUVA8Planes( + const SkYUVASizeInfo& size_info, + const SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + void* planes[4]) { + return paint_image_generator_->GetYUVA8Planes(size_info, indices, planes, + frame_index_, uniqueID()); } } // namespace cc diff --git a/chromium/cc/paint/skia_paint_image_generator.h b/chromium/cc/paint/skia_paint_image_generator.h index c93e03b0a99..55068c2f988 100644 --- a/chromium/cc/paint/skia_paint_image_generator.h +++ b/chromium/cc/paint/skia_paint_image_generator.h @@ -25,10 +25,12 @@ class CC_PAINT_EXPORT SkiaPaintImageGenerator final : public SkImageGenerator { void* pixels, size_t row_bytes, const Options& options) override; - bool onQueryYUV8(SkYUVSizeInfo* size_info, - SkYUVColorSpace* color_space) const override; - bool onGetYUV8Planes(const SkYUVSizeInfo& size_info, - void* planes[3]) override; + bool onQueryYUVA8(SkYUVASizeInfo* size_info, + SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + SkYUVColorSpace* color_space) const override; + bool onGetYUVA8Planes(const SkYUVASizeInfo& size_info, + const SkYUVAIndex indices[SkYUVAIndex::kIndexCount], + void* planes[3]) override; private: sk_sp<PaintImageGenerator> paint_image_generator_; diff --git a/chromium/cc/paint/skottie_wrapper.cc b/chromium/cc/paint/skottie_wrapper.cc new file mode 100644 index 00000000000..ad5fb740898 --- /dev/null +++ b/chromium/cc/paint/skottie_wrapper.cc @@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/paint/skottie_wrapper.h" + +#include "base/memory/ref_counted_memory.h" +#include "base/trace_event/trace_event.h" +#include "third_party/skia/include/core/SkStream.h" + +namespace cc { + +SkottieWrapper::SkottieWrapper( + const scoped_refptr<base::RefCountedMemory>& data_stream) { + TRACE_EVENT0("cc", "SkottieWrapper Parse"); + SkMemoryStream sk_stream(data_stream->front(), data_stream->size()); + animation_ = skottie::Animation::Make(&sk_stream); + DCHECK(animation_); +} + +SkottieWrapper::SkottieWrapper(std::unique_ptr<SkMemoryStream> stream) + : animation_(skottie::Animation::Make(stream.get())) { + DCHECK(animation_); +} + +SkottieWrapper::~SkottieWrapper() {} + +void SkottieWrapper::Draw(SkCanvas* canvas, float t, const SkRect& rect) { + base::AutoLock lock(lock_); + animation_->seek(t); + animation_->render(canvas, &rect); +} + +} // namespace cc diff --git a/chromium/cc/paint/skottie_wrapper.h b/chromium/cc/paint/skottie_wrapper.h new file mode 100644 index 00000000000..f4e312ec029 --- /dev/null +++ b/chromium/cc/paint/skottie_wrapper.h @@ -0,0 +1,55 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_PAINT_SKOTTIE_WRAPPER_H_ +#define CC_PAINT_SKOTTIE_WRAPPER_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "cc/paint/paint_export.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/modules/skottie/include/Skottie.h" + +class SkCanvas; +class SkMemoryStream; + +namespace base { +class RefCountedMemory; +} // namespace base + +namespace cc { + +// A wrapper over Skia's Skottie object that can be shared by multiple +// SkiaVectorAnimation objects. This class is thread safe when performing a draw +// on an SkCanvas. +class CC_PAINT_EXPORT SkottieWrapper + : public base::RefCountedThreadSafe<SkottieWrapper> { + public: + explicit SkottieWrapper( + const scoped_refptr<base::RefCountedMemory>& data_stream); + explicit SkottieWrapper(std::unique_ptr<SkMemoryStream> stream); + + // A thread safe call that will draw an image with bounds |rect| for the + // frame at normalized time instant |t| onto the |canvas|. + void Draw(SkCanvas* canvas, float t, const SkRect& rect); + + float duration() const { return animation_->duration(); } + SkSize size() const { return animation_->size(); } + + private: + friend class base::RefCountedThreadSafe<SkottieWrapper>; + ~SkottieWrapper(); + + base::Lock lock_; + sk_sp<skottie::Animation> animation_; + + DISALLOW_COPY_AND_ASSIGN(SkottieWrapper); +}; + +} // namespace cc + +#endif // CC_PAINT_SKOTTIE_WRAPPER_H_ diff --git a/chromium/cc/paint/solid_color_analyzer.cc b/chromium/cc/paint/solid_color_analyzer.cc index 2ecc07bb767..12ad8e46f1d 100644 --- a/chromium/cc/paint/solid_color_analyzer.cc +++ b/chromium/cc/paint/solid_color_analyzer.cc @@ -213,6 +213,7 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor( &is_transparent, &color); break; } + case PaintOpType::DrawSkottie: case PaintOpType::DrawTextBlob: // Anything that has to do a save layer is probably not solid. As it will // likely need more than one draw op. diff --git a/chromium/cc/paint/transfer_cache_entry.cc b/chromium/cc/paint/transfer_cache_entry.cc index bb34a4cada8..d87ac461b87 100644 --- a/chromium/cc/paint/transfer_cache_entry.cc +++ b/chromium/cc/paint/transfer_cache_entry.cc @@ -9,7 +9,6 @@ #include "base/logging.h" #include "cc/paint/color_space_transfer_cache_entry.h" #include "cc/paint/image_transfer_cache_entry.h" -#include "cc/paint/path_transfer_cache_entry.h" #include "cc/paint/raw_memory_transfer_cache_entry.h" #include "cc/paint/shader_transfer_cache_entry.h" @@ -24,11 +23,9 @@ std::unique_ptr<ServiceTransferCacheEntry> ServiceTransferCacheEntry::Create( return std::make_unique<ServiceImageTransferCacheEntry>(); case TransferCacheEntryType::kColorSpace: return std::make_unique<ServiceColorSpaceTransferCacheEntry>(); - case TransferCacheEntryType::kPath: - return std::make_unique<ServicePathTransferCacheEntry>(); case TransferCacheEntryType::kShader: - // ServiceShaderTransferCache is only created via CreateLocalEntry - // and is never serialized/deserialized. + // ServiceShader/TextBlobTransferCache is only created via + // CreateLocalEntry and is never serialized/deserialized. return nullptr; } @@ -50,7 +47,6 @@ bool ServiceTransferCacheEntry::UsesGrContext(TransferCacheEntryType type) { switch (type) { case TransferCacheEntryType::kRawMemory: case TransferCacheEntryType::kColorSpace: - case TransferCacheEntryType::kPath: case TransferCacheEntryType::kShader: return false; case TransferCacheEntryType::kImage: diff --git a/chromium/cc/paint/transfer_cache_entry.h b/chromium/cc/paint/transfer_cache_entry.h index 55f1ce7dba3..374607e2497 100644 --- a/chromium/cc/paint/transfer_cache_entry.h +++ b/chromium/cc/paint/transfer_cache_entry.h @@ -23,7 +23,6 @@ enum class TransferCacheEntryType : uint32_t { kRawMemory, kImage, kColorSpace, - kPath, kShader, // Add new entries above this line, make sure to update kLast. kLast = kShader, diff --git a/chromium/cc/paint/transfer_cache_serialize_helper.cc b/chromium/cc/paint/transfer_cache_serialize_helper.cc index 1baec7dddec..f50f150f7c7 100644 --- a/chromium/cc/paint/transfer_cache_serialize_helper.cc +++ b/chromium/cc/paint/transfer_cache_serialize_helper.cc @@ -27,13 +27,14 @@ bool TransferCacheSerializeHelper::LockEntry(TransferCacheEntryType type, return true; } -void TransferCacheSerializeHelper::CreateEntry( - const ClientTransferCacheEntry& entry) { +size_t TransferCacheSerializeHelper::CreateEntry( + const ClientTransferCacheEntry& entry, + char* memory) { // We shouldn't be creating entries if they were already created or locked. EntryKey key(entry.Type(), entry.Id()); DCHECK_EQ(added_entries_.count(key), 0u); - CreateEntryInternal(entry); added_entries_.insert(key); + return CreateEntryInternal(entry, memory); } void TransferCacheSerializeHelper::FlushEntries() { diff --git a/chromium/cc/paint/transfer_cache_serialize_helper.h b/chromium/cc/paint/transfer_cache_serialize_helper.h index 7fd947aaec8..1a204407538 100644 --- a/chromium/cc/paint/transfer_cache_serialize_helper.h +++ b/chromium/cc/paint/transfer_cache_serialize_helper.h @@ -19,7 +19,10 @@ class CC_PAINT_EXPORT TransferCacheSerializeHelper { virtual ~TransferCacheSerializeHelper(); bool LockEntry(TransferCacheEntryType type, uint32_t id); - void CreateEntry(const ClientTransferCacheEntry& entry); + // The PaintOpWriter passes the address where the transfer cache may inline + // this entry. The size returned is the memory used if the entry is inlined, + // or 0u if no data is inlined. + size_t CreateEntry(const ClientTransferCacheEntry& entry, char* memory); void FlushEntries(); void AssertLocked(TransferCacheEntryType type, uint32_t id); @@ -28,7 +31,8 @@ class CC_PAINT_EXPORT TransferCacheSerializeHelper { using EntryKey = std::pair<TransferCacheEntryType, uint32_t>; virtual bool LockEntryInternal(const EntryKey& key) = 0; - virtual void CreateEntryInternal(const ClientTransferCacheEntry& entry) = 0; + virtual size_t CreateEntryInternal(const ClientTransferCacheEntry& entry, + char* memory) = 0; virtual void FlushEntriesInternal(std::set<EntryKey> keys) = 0; private: diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc index f003d24f80e..f24917ab29d 100644 --- a/chromium/cc/paint/transfer_cache_unittest.cc +++ b/chromium/cc/paint/transfer_cache_unittest.cc @@ -20,6 +20,7 @@ #include "gpu/command_buffer/service/service_transfer_cache.h" #include "gpu/config/gpu_switches.h" #include "gpu/ipc/raster_in_process_context.h" +#include "gpu/ipc/test_gpu_thread_holder.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkImage.h" #include "ui/gl/gl_implementation.h" @@ -47,8 +48,8 @@ class TransferCacheTest : public testing::Test { context_ = std::make_unique<gpu::RasterInProcessContext>(); auto result = context_->Initialize( - /*service=*/nullptr, attribs, gpu::SharedMemoryLimits(), - &gpu_memory_buffer_manager_, &image_factory_, + gpu::GetTestGpuThreadHolder()->GetTaskExecutor(), attribs, + gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_, &image_factory_, /*gpu_channel_manager_delegate=*/nullptr, nullptr, nullptr); ASSERT_EQ(result, gpu::ContextResult::kSuccess); @@ -177,7 +178,9 @@ TEST_F(TransferCacheTest, CountEviction) { EXPECT_EQ(service_cache->cache_size_for_testing(), 20u); } -TEST_F(TransferCacheTest, RawMemoryTransfer) { +// This tests a size that is small enough that the transfer buffer is used +// inside of RasterImplementation::MapTransferCacheEntry. +TEST_F(TransferCacheTest, RawMemoryTransferSmall) { auto* service_cache = ServiceTransferCache(); // Create an entry with some initialized data. @@ -202,6 +205,33 @@ TEST_F(TransferCacheTest, RawMemoryTransfer) { EXPECT_EQ(data, service_data); } +// This tests a size that is large enough that mapped memory is used inside +// of RasterImplementation::MapTransferCacheEntry. +TEST_F(TransferCacheTest, RawMemoryTransferLarge) { + auto* service_cache = ServiceTransferCache(); + + // Create an entry with some initialized data. + std::vector<uint8_t> data; + data.resize(1500); + for (size_t i = 0; i < data.size(); ++i) { + data[i] = i; + } + + // Add the entry to the transfer cache + ClientRawMemoryTransferCacheEntry client_entry(data); + CreateEntry(client_entry); + ri()->Finish(); + + // Validate service-side data matches. + ServiceTransferCacheEntry* service_entry = + service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( + decoder_id(), client_entry.Type(), client_entry.Id())); + EXPECT_EQ(service_entry->Type(), client_entry.Type()); + const std::vector<uint8_t> service_data = + static_cast<ServiceRawMemoryTransferCacheEntry*>(service_entry)->data(); + EXPECT_EQ(data, service_data); +} + TEST_F(TransferCacheTest, ImageMemoryTransfer) { // TODO(ericrk): This test doesn't work. crbug.com/859619 return; diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc index 1e4e21bb134..fc981249cd6 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc @@ -13,7 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/raster/raster_source.h" #include "cc/trees/layer_tree_frame_sink.h" #include "components/viz/common/resources/bitmap_allocation.h" diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc index 2b9b386ee08..2a731285a2c 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.cc +++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc @@ -134,7 +134,8 @@ static void RasterizeSourceOOP( if (mailbox->IsZero()) { DCHECK(!sync_token.HasData()); auto* sii = context_provider->SharedImageInterface(); - uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER; + uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER | + gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; if (texture_is_overlay_candidate) flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; *mailbox = sii->CreateSharedImage(resource_format, resource_size, @@ -144,10 +145,6 @@ static void RasterizeSourceOOP( ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); } - GLuint texture_id = ri->CreateAndConsumeTexture( - texture_is_overlay_candidate, gfx::BufferUsage::SCANOUT, resource_format, - mailbox->name); - // TODO(enne): Use the |texture_target|? GpuMemoryBuffer backed textures don't // use GL_TEXTURE_2D. ri->BeginRasterCHROMIUM(raster_source->background_color(), msaa_sample_count, @@ -171,8 +168,6 @@ static void RasterizeSourceOOP( // TODO(ericrk): Handle unpremultiply+dither for 4444 cases. // https://crbug.com/789153 - - ri->DeleteTextures(1, &texture_id); } static void RasterizeSource( diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc index 562d2e21bfe..75e11544218 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc @@ -366,61 +366,50 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( bool mailbox_texture_is_overlay_candidate, const gpu::SyncToken& sync_token, const gfx::ColorSpace& color_space) { - viz::RasterContextProvider::ScopedRasterContextLock scoped_context( - worker_context_provider_); - gpu::raster::RasterInterface* ri = scoped_context.RasterInterface(); - DCHECK(ri); + auto* sii = worker_context_provider_->SharedImageInterface(); + DCHECK(sii); + + if (!staging_buffer->gpu_memory_buffer.get()) { + // If GpuMemoryBuffer allocation failed (https://crbug.com/554541), then + // we don't have anything to give to copy into the resource. We report a + // zero mailbox that will result in checkerboarding, and be treated as OOM + // which should retry. + if (!mailbox->IsZero()) { + sii->DestroySharedImage(sync_token, *mailbox); + mailbox->SetZero(); + } + return gpu::SyncToken(); + } if (mailbox->IsZero()) { - auto* sii = worker_context_provider_->SharedImageInterface(); uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER; if (mailbox_texture_is_overlay_candidate) flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; *mailbox = sii->CreateSharedImage(resource_format, resource_size, color_space, flags); - ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + } + + // Create staging shared image. + if (staging_buffer->mailbox.IsZero()) { + staging_buffer->mailbox = sii->CreateSharedImage( + staging_buffer->gpu_memory_buffer.get(), gpu_memory_buffer_manager_, + color_space, gpu::SHARED_IMAGE_USAGE_RASTER); } else { - ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); + sii->UpdateSharedImage(staging_buffer->sync_token, staging_buffer->mailbox); } + viz::RasterContextProvider::ScopedRasterContextLock scoped_context( + worker_context_provider_); + gpu::raster::RasterInterface* ri = scoped_context.RasterInterface(); + DCHECK(ri); + ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); + ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); GLuint mailbox_texture_id = ri->CreateAndConsumeTexture( mailbox_texture_is_overlay_candidate, gfx::BufferUsage::SCANOUT, resource_format, mailbox->name); - - // Create and bind staging texture. - if (!staging_buffer->texture_id) { - staging_buffer->texture_id = - ri->CreateTexture(true, StagingBufferUsage(), staging_buffer->format); - ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_MIN_FILTER, - GL_NEAREST); - ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_MAG_FILTER, - GL_NEAREST); - ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - ri->TexParameteri(staging_buffer->texture_id, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - } - - // Create and bind image. - if (!staging_buffer->image_id) { - if (staging_buffer->gpu_memory_buffer) { - staging_buffer->image_id = ri->CreateImageCHROMIUM( - staging_buffer->gpu_memory_buffer->AsClientBuffer(), - staging_buffer->size.width(), staging_buffer->size.height(), - GLInternalFormat(staging_buffer->format)); - ri->BindTexImage2DCHROMIUM(staging_buffer->texture_id, - staging_buffer->image_id); - } - } else { - ri->ReleaseTexImage2DCHROMIUM(staging_buffer->texture_id, - staging_buffer->image_id); - ri->BindTexImage2DCHROMIUM(staging_buffer->texture_id, - staging_buffer->image_id); - } - - // Unbind staging texture. - // TODO(vmiura): Need a way to ensure we don't hold onto bindings? - // ri->BindTexture(image_target, 0); + GLuint staging_texture_id = ri->CreateAndConsumeTexture( + true, StagingBufferUsage(), staging_buffer->format, + staging_buffer->mailbox.name); // Do not use queries unless COMMANDS_COMPLETED queries are supported, or // COMMANDS_ISSUED queries are sufficient. @@ -467,8 +456,8 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( int rows_to_copy = std::min(chunk_size_in_rows, height - y); DCHECK_GT(rows_to_copy, 0); - ri->CopySubTexture(staging_buffer->texture_id, mailbox_texture_id, 0, y, 0, - y, rect_to_copy.width(), rows_to_copy); + ri->CopySubTexture(staging_texture_id, mailbox_texture_id, 0, y, 0, y, + rect_to_copy.width(), rows_to_copy); y += rows_to_copy; // Increment |bytes_scheduled_since_last_flush_| by the amount of memory @@ -484,11 +473,20 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( if (query_target != GL_NONE) ri->EndQueryEXT(query_target); - ri->DeleteTextures(1, &mailbox_texture_id); + GLuint textures_to_delete[] = {mailbox_texture_id, staging_texture_id}; + ri->DeleteTextures(2, textures_to_delete); // Generate sync token on the worker context that will be sent to and waited // for by the display compositor before using the content generated here. - return viz::ClientResourceProvider::GenerateSyncTokenHelper(ri); + // The same sync token is used to synchronize operations on the staging + // buffer. Note, the query completion is generally enough to guarantee + // ordering, but there are some paths (e.g. + // StagingBufferPool::ReduceMemoryUsage) that may destroy the staging buffer + // without waiting for the query completion. + gpu::SyncToken out_sync_token = + viz::ClientResourceProvider::GenerateSyncTokenHelper(ri); + staging_buffer->sync_token = out_sync_token; + return out_sync_token; } gfx::BufferUsage OneCopyRasterBufferProvider::StagingBufferUsage() const { diff --git a/chromium/cc/raster/playback_image_provider.cc b/chromium/cc/raster/playback_image_provider.cc index 50305d1b2a5..7aef7601c14 100644 --- a/chromium/cc/raster/playback_image_provider.cc +++ b/chromium/cc/raster/playback_image_provider.cc @@ -18,10 +18,8 @@ void UnrefImageFromCache(DrawImage draw_image, PlaybackImageProvider::PlaybackImageProvider( ImageDecodeCache* cache, - const gfx::ColorSpace& target_color_space, base::Optional<Settings>&& settings) : cache_(cache), - target_color_space_(target_color_space), settings_(std::move(settings)) { DCHECK(cache_); } @@ -53,7 +51,7 @@ PlaybackImageProvider::GetDecodedDrawImage(const DrawImage& draw_image) { ? PaintImage::kDefaultFrameIndex : it->second; - DrawImage adjusted_image(draw_image, 1.f, frame_index, target_color_space_); + DrawImage adjusted_image(draw_image, 1.f, frame_index); if (!cache_->UseCacheForDrawImage(adjusted_image)) { return ScopedDecodedDrawImage(DecodedDrawImage( paint_image.GetSkImage(), SkSize::Make(0, 0), SkSize::Make(1.f, 1.f), diff --git a/chromium/cc/raster/playback_image_provider.h b/chromium/cc/raster/playback_image_provider.h index a33092d2b5b..990835c040f 100644 --- a/chromium/cc/raster/playback_image_provider.h +++ b/chromium/cc/raster/playback_image_provider.h @@ -35,7 +35,6 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider { // If no settings are provided, all images are skipped during rasterization. PlaybackImageProvider(ImageDecodeCache* cache, - const gfx::ColorSpace& target_color_space, base::Optional<Settings>&& settings); ~PlaybackImageProvider() override; @@ -48,7 +47,6 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider { private: ImageDecodeCache* cache_; - gfx::ColorSpace target_color_space_; base::Optional<Settings> settings_; DISALLOW_COPY_AND_ASSIGN(PlaybackImageProvider); diff --git a/chromium/cc/raster/playback_image_provider_unittest.cc b/chromium/cc/raster/playback_image_provider_unittest.cc index dd4f6a4a9e8..dbc5ba0c3e2 100644 --- a/chromium/cc/raster/playback_image_provider_unittest.cc +++ b/chromium/cc/raster/playback_image_provider_unittest.cc @@ -66,7 +66,7 @@ class MockDecodeCache : public StubDecodeCache { TEST(PlaybackImageProviderTest, SkipsAllImages) { MockDecodeCache cache; - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), base::nullopt); + PlaybackImageProvider provider(&cache, base::nullopt); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -93,8 +93,7 @@ TEST(PlaybackImageProviderTest, SkipsSomeImages) { settings.emplace(); settings->images_to_skip = {skip_image.stable_id()}; - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), - std::move(settings)); + PlaybackImageProvider provider(&cache, std::move(settings)); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -108,8 +107,7 @@ TEST(PlaybackImageProviderTest, RefAndUnrefDecode) { base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), - std::move(settings)); + PlaybackImageProvider provider(&cache, std::move(settings)); { SkRect rect = SkRect::MakeWH(10, 10); @@ -137,8 +135,7 @@ TEST(PlaybackImageProviderTest, SwapsGivenFrames) { settings.emplace(); settings->image_to_current_frame_index = image_to_frame; - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), - std::move(settings)); + PlaybackImageProvider provider(&cache, std::move(settings)); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -154,8 +151,7 @@ TEST(PlaybackImageProviderTest, BitmapImages) { base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), - std::move(settings)); + PlaybackImageProvider provider(&cache, std::move(settings)); { SkIRect rect = SkIRect::MakeWH(10, 10); @@ -176,8 +172,7 @@ TEST(PlaybackImageProviderTest, IgnoresImagesNotSupportedByCache) { cache.set_use_cache_for_draw_image(false); base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, gfx::ColorSpace(), - std::move(settings)); + PlaybackImageProvider provider(&cache, std::move(settings)); { SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc index bbdd6f57bda..63dd9fd95d1 100644 --- a/chromium/cc/raster/raster_buffer_provider_perftest.cc +++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc @@ -86,7 +86,7 @@ class PerfContextProvider capabilities_.sync_query = true; raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>( - context_gl_.get(), nullptr, capabilities_); + context_gl_.get(), capabilities_); } // viz::ContextProvider implementation. diff --git a/chromium/cc/raster/raster_source_unittest.cc b/chromium/cc/raster/raster_source_unittest.cc index 311cb5eef2b..b9100522081 100644 --- a/chromium/cc/raster/raster_source_unittest.cc +++ b/chromium/cc/raster/raster_source_unittest.cc @@ -211,25 +211,19 @@ TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { // Tile sized iterators. These should find only one pixel ref. { - gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB(); std::vector<const DrawImage*> images; raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), &images); EXPECT_EQ(1u, images.size()); - DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex, - target_color_space); + DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex); EXPECT_EQ(discardable_image[0][0], images[0]->paint_image()); - EXPECT_EQ(target_color_space, image.target_color_space()); } // Shifted tile sized iterators. These should find only one pixel ref. { - gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); std::vector<const DrawImage*> images; raster->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), &images); EXPECT_EQ(1u, images.size()); - DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex, - target_color_space); + DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex); EXPECT_EQ(discardable_image[1][1], images[0]->paint_image()); - EXPECT_EQ(target_color_space, image.target_color_space()); } // Ensure there's no discardable pixel refs in the empty cell { diff --git a/chromium/cc/raster/single_thread_task_graph_runner.cc b/chromium/cc/raster/single_thread_task_graph_runner.cc index e17ec83f13f..0bb96a42a42 100644 --- a/chromium/cc/raster/single_thread_task_graph_runner.cc +++ b/chromium/cc/raster/single_thread_task_graph_runner.cc @@ -18,7 +18,9 @@ SingleThreadTaskGraphRunner::SingleThreadTaskGraphRunner() : lock_(), has_ready_to_run_tasks_cv_(&lock_), has_namespaces_with_finished_running_tasks_cv_(&lock_), - shutdown_(false) {} + shutdown_(false) { + has_ready_to_run_tasks_cv_.declare_only_used_while_idle(); +} SingleThreadTaskGraphRunner::~SingleThreadTaskGraphRunner() = default; @@ -81,7 +83,8 @@ void SingleThreadTaskGraphRunner::WaitForTasksToFinishRunning( { base::AutoLock lock(lock_); - base::ThreadRestrictions::ScopedAllowWait allow_wait; + // http://crbug.com/902823 + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; auto* task_namespace = work_queue_.GetNamespaceForToken(token); diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc index a24fe9a16fb..a02c43e4e98 100644 --- a/chromium/cc/raster/staging_buffer_pool.cc +++ b/chromium/cc/raster/staging_buffer_pool.cc @@ -12,7 +12,9 @@ #include "cc/base/container_util.h" #include "components/viz/common/gpu/raster_context_provider.h" #include "components/viz/common/resources/resource_sizes.h" +#include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/raster_interface.h" +#include "gpu/command_buffer/client/shared_image_interface.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -68,23 +70,19 @@ StagingBuffer::StagingBuffer(const gfx::Size& size, viz::ResourceFormat format) : size(size), format(format) {} StagingBuffer::~StagingBuffer() { - DCHECK_EQ(texture_id, 0u); - DCHECK_EQ(image_id, 0u); + DCHECK(mailbox.IsZero()); DCHECK_EQ(query_id, 0u); } -void StagingBuffer::DestroyGLResources(gpu::raster::RasterInterface* ri) { +void StagingBuffer::DestroyGLResources(gpu::raster::RasterInterface* ri, + gpu::SharedImageInterface* sii) { if (query_id) { ri->DeleteQueriesEXT(1, &query_id); query_id = 0; } - if (image_id) { - ri->DestroyImageCHROMIUM(image_id); - image_id = 0; - } - if (texture_id) { - ri->DeleteTextures(1, &texture_id); - texture_id = 0; + if (!mailbox.IsZero()) { + sii->DestroySharedImage(sync_token, mailbox); + mailbox.SetZero(); } } @@ -94,9 +92,9 @@ void StagingBuffer::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, if (!gpu_memory_buffer) return; - gfx::GpuMemoryBufferId buffer_id = gpu_memory_buffer->GetId(); + // Use |this| as the id, which works with multiple StagingBuffers. std::string buffer_dump_name = - base::StringPrintf("cc/one_copy/staging_memory/buffer_%d", buffer_id.id); + base::StringPrintf("cc/one_copy/staging_memory/buffer_%p", this); MemoryAllocatorDump* buffer_dump = pmd->CreateAllocatorDump(buffer_dump_name); uint64_t buffer_size_in_bytes = @@ -248,6 +246,8 @@ std::unique_ptr<StagingBuffer> StagingBufferPool::AcquireStagingBuffer( worker_context_provider_); gpu::raster::RasterInterface* ri = scoped_context.RasterInterface(); + gpu::SharedImageInterface* sii = + worker_context_provider_->SharedImageInterface(); DCHECK(ri); // Check if any busy buffers have become available. @@ -324,7 +324,7 @@ std::unique_ptr<StagingBuffer> StagingBufferPool::AcquireStagingBuffer( if (free_buffers_.empty()) break; - free_buffers_.front()->DestroyGLResources(ri); + free_buffers_.front()->DestroyGLResources(ri, sii); MarkStagingBufferAsBusy(free_buffers_.front().get()); RemoveStagingBuffer(free_buffers_.front().get()); free_buffers_.pop_front(); @@ -395,14 +395,19 @@ void StagingBufferPool::ReleaseBuffersNotUsedSince(base::TimeTicks time) { gpu::raster::RasterInterface* ri = scoped_context.RasterInterface(); DCHECK(ri); + gpu::SharedImageInterface* sii = + worker_context_provider_->SharedImageInterface(); + DCHECK(sii); + bool destroyed_buffers = false; // Note: Front buffer is guaranteed to be LRU so we can stop releasing // buffers as soon as we find a buffer that has been used since |time|. while (!free_buffers_.empty()) { if (free_buffers_.front()->last_usage > time) return; - free_buffers_.front()->DestroyGLResources(ri); + destroyed_buffers = true; + free_buffers_.front()->DestroyGLResources(ri, sii); MarkStagingBufferAsBusy(free_buffers_.front().get()); RemoveStagingBuffer(free_buffers_.front().get()); free_buffers_.pop_front(); @@ -412,10 +417,16 @@ void StagingBufferPool::ReleaseBuffersNotUsedSince(base::TimeTicks time) { if (busy_buffers_.front()->last_usage > time) return; - busy_buffers_.front()->DestroyGLResources(ri); + destroyed_buffers = true; + busy_buffers_.front()->DestroyGLResources(ri, sii); RemoveStagingBuffer(busy_buffers_.front().get()); busy_buffers_.pop_front(); } + + if (destroyed_buffers) { + ri->OrderingBarrierCHROMIUM(); + worker_context_provider_->ContextSupport()->FlushPendingWork(); + } } } diff --git a/chromium/cc/raster/staging_buffer_pool.h b/chromium/cc/raster/staging_buffer_pool.h index 687b0066588..cfd0f3a414c 100644 --- a/chromium/cc/raster/staging_buffer_pool.h +++ b/chromium/cc/raster/staging_buffer_pool.h @@ -22,6 +22,8 @@ #include "cc/cc_export.h" #include "components/viz/common/resources/resource_format.h" #include "gpu/command_buffer/common/gl2_types.h" +#include "gpu/command_buffer/common/mailbox.h" +#include "gpu/command_buffer/common/sync_token.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -32,6 +34,7 @@ namespace gpu { namespace raster { class RasterInterface; } +class SharedImageInterface; } // namespace gpu namespace viz { @@ -44,7 +47,8 @@ struct StagingBuffer { StagingBuffer(const gfx::Size& size, viz::ResourceFormat format); ~StagingBuffer(); - void DestroyGLResources(gpu::raster::RasterInterface* gl); + void DestroyGLResources(gpu::raster::RasterInterface* gl, + gpu::SharedImageInterface* sii); void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, viz::ResourceFormat format, bool is_free) const; @@ -58,11 +62,11 @@ struct StagingBuffer { // GpuMemoryBuffer. std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; - // Id for image used to import the GpuMemoryBuffer to command buffer. - GLuint image_id = 0; + // Mailbox for the shared image bound to the GpuMemoryBuffer. + gpu::Mailbox mailbox; - // Id for texture that's bound to the GpuMemoryBuffer image. - GLuint texture_id = 0; + // Sync token for the last RasterInterface operations using the shared image. + gpu::SyncToken sync_token; // Id of command buffer query that tracks use of this staging buffer by the // GPU. In general, GPU synchronization is necessary for native diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc index 21010d76efd..b61b669e57e 100644 --- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc @@ -9,16 +9,19 @@ #include <algorithm> #include "base/macros.h" +#include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/resources/resource_pool.h" #include "components/viz/client/client_resource_provider.h" #include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/resource_format_utils.h" -#include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" +#include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" +#include "gpu/command_buffer/common/shared_image_trace_utils.h" +#include "gpu/command_buffer/common/shared_image_usage.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -32,13 +35,12 @@ constexpr static auto kBufferUsage = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE; class ZeroCopyGpuBacking : public ResourcePool::GpuBacking { public: ~ZeroCopyGpuBacking() override { - gpu::gles2::GLES2Interface* gl = compositor_context_provider->ContextGL(); + if (mailbox.IsZero()) + return; if (returned_sync_token.HasData()) - gl->WaitSyncTokenCHROMIUM(returned_sync_token.GetConstData()); - if (texture_id) - gl->DeleteTextures(1, &texture_id); - if (image_id) - gl->DestroyImageCHROMIUM(image_id); + shared_image_interface->DestroySharedImage(returned_sync_token, mailbox); + else if (mailbox_sync_token.HasData()) + shared_image_interface->DestroySharedImage(mailbox_sync_token, mailbox); } void OnMemoryDump( @@ -52,16 +54,11 @@ class ZeroCopyGpuBacking : public ResourcePool::GpuBacking { importance); } - // The ContextProvider used to clean up the texture and image ids. - viz::ContextProvider* compositor_context_provider = nullptr; + // The SharedImageInterface used to clean up the shared image. + gpu::SharedImageInterface* shared_image_interface = nullptr; // The backing for zero-copy gpu resources. The |texture_id| is bound to // this. std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; - // The texture id bound to the GpuMemoryBuffer. - uint32_t texture_id = 0; - // The image id that associates the |gpu_memory_buffer| and the - // |texture_id|. - uint32_t image_id = 0; }; // RasterBuffer for the zero copy upload, which is given to the raster worker @@ -69,7 +66,6 @@ class ZeroCopyGpuBacking : public ResourcePool::GpuBacking { class ZeroCopyRasterBufferImpl : public RasterBuffer { public: ZeroCopyRasterBufferImpl( - viz::ContextProvider* context_provider, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, const ResourcePool::InUsePoolResource& in_use_resource, ZeroCopyGpuBacking* backing) @@ -81,77 +77,33 @@ class ZeroCopyRasterBufferImpl : public RasterBuffer { gpu_memory_buffer_(std::move(backing_->gpu_memory_buffer)) {} ~ZeroCopyRasterBufferImpl() override { + // If GpuMemoryBuffer allocation failed (https://crbug.com/554541), then + // we don't have anything to give to the display compositor, so we report a + // zero mailbox that will result in checkerboarding. + if (!gpu_memory_buffer_) { + DCHECK(backing_->mailbox.IsZero()); + return; + } + // This is destroyed on the compositor thread when raster is complete, but // before the backing is prepared for export to the display compositor. So // we can set up the texture and SyncToken here. // TODO(danakj): This could be done with the worker context in Playback. Do // we need to do things in IsResourceReadyToDraw() and OrderingBarrier then? - gpu::gles2::GLES2Interface* gl = - backing_->compositor_context_provider->ContextGL(); - const gpu::Capabilities& caps = - backing_->compositor_context_provider->ContextCapabilities(); - - if (backing_->returned_sync_token.HasData()) { - gl->WaitSyncTokenCHROMIUM(backing_->returned_sync_token.GetConstData()); - backing_->returned_sync_token = gpu::SyncToken(); - } - - if (!backing_->texture_id) { - // Make a texture and a mailbox for export of the GpuMemoryBuffer to the - // display compositor. - gl->GenTextures(1, &backing_->texture_id); - backing_->texture_target = gpu::GetBufferTextureTarget( - kBufferUsage, viz::BufferFormat(resource_format_), caps); - gl->ProduceTextureDirectCHROMIUM(backing_->texture_id, - backing_->mailbox.name); - backing_->overlay_candidate = true; - // This RasterBufferProvider will modify the resource outside of the - // GL command stream. So resources should not become available for reuse - // until they are not in use by the gpu anymore, which a fence is used to - // determine. - backing_->wait_on_fence_required = true; - - gl->BindTexture(backing_->texture_target, backing_->texture_id); - gl->TexParameteri(backing_->texture_target, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - gl->TexParameteri(backing_->texture_target, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - gl->TexParameteri(backing_->texture_target, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - gl->TexParameteri(backing_->texture_target, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); + gpu::SharedImageInterface* sii = backing_->shared_image_interface; + if (backing_->mailbox.IsZero()) { + uint32_t usage = + gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT; + // Make a mailbox for export of the GpuMemoryBuffer to the display + // compositor. + backing_->mailbox = sii->CreateSharedImage(gpu_memory_buffer_.get(), + gpu_memory_buffer_manager_, + resource_color_space_, usage); } else { - gl->BindTexture(backing_->texture_target, backing_->texture_id); + sii->UpdateSharedImage(backing_->returned_sync_token, backing_->mailbox); } - if (!backing_->image_id) { - // If GpuMemoryBuffer allocation failed (https://crbug.com/554541), then - // we don't have anything to give to the display compositor, but also no - // way to report an error, so we just make a texture but don't bind - // anything to it. Many blink layout tests on macOS fail to have no - // |gpu_memory_buffer_| here, so any error reporting will spam console - // logs (https://crbug.com/871031). - if (gpu_memory_buffer_) { - backing_->image_id = gl->CreateImageCHROMIUM( - gpu_memory_buffer_->AsClientBuffer(), resource_size_.width(), - resource_size_.height(), viz::GLInternalFormat(resource_format_)); - gl->BindTexImage2DCHROMIUM(backing_->texture_target, - backing_->image_id); - } - } else { - gl->ReleaseTexImage2DCHROMIUM(backing_->texture_target, - backing_->image_id); - gl->BindTexImage2DCHROMIUM(backing_->texture_target, backing_->image_id); - } - if (backing_->image_id && resource_color_space_.IsValid()) { - gl->SetColorSpaceMetadataCHROMIUM( - backing_->texture_id, - reinterpret_cast<GLColorSpace>(&resource_color_space_)); - } - gl->BindTexture(backing_->texture_target, 0); - - backing_->mailbox_sync_token = - viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); + backing_->mailbox_sync_token = sii->GenUnverifiedSyncToken(); backing_->gpu_memory_buffer = std::move(gpu_memory_buffer_); } @@ -225,15 +177,25 @@ ZeroCopyRasterBufferProvider::AcquireBufferForRaster( uint64_t previous_content_id) { if (!resource.gpu_backing()) { auto backing = std::make_unique<ZeroCopyGpuBacking>(); - backing->compositor_context_provider = compositor_context_provider_; + const gpu::Capabilities& caps = + compositor_context_provider_->ContextCapabilities(); + backing->texture_target = gpu::GetBufferTextureTarget( + kBufferUsage, BufferFormat(resource.format()), caps); + backing->overlay_candidate = true; + // This RasterBufferProvider will modify the resource outside of the + // GL command stream. So resources should not become available for reuse + // until they are not in use by the gpu anymore, which a fence is used + // to determine. + backing->wait_on_fence_required = true; + backing->shared_image_interface = + compositor_context_provider_->SharedImageInterface(); resource.set_gpu_backing(std::move(backing)); } ZeroCopyGpuBacking* backing = static_cast<ZeroCopyGpuBacking*>(resource.gpu_backing()); - return std::make_unique<ZeroCopyRasterBufferImpl>( - compositor_context_provider_, gpu_memory_buffer_manager_, resource, - backing); + return std::make_unique<ZeroCopyRasterBufferImpl>(gpu_memory_buffer_manager_, + resource, backing); } void ZeroCopyRasterBufferProvider::Flush() {} diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index 05d6fd97386..2e2fd3fab8f 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -16,6 +16,7 @@ #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/default_tick_clock.h" #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" #include "cc/base/container_util.h" @@ -67,6 +68,7 @@ bool ResourceMeetsSizeRequirements(const gfx::Size& requested_size, } // namespace constexpr base::TimeDelta ResourcePool::kDefaultExpirationDelay; +constexpr base::TimeDelta ResourcePool::kDefaultMaxFlushDelay; void ResourcePool::GpuBacking::InitOverlayCandidateAndTextureTarget( const viz::ResourceFormat format, @@ -95,6 +97,8 @@ ResourcePool::ResourcePool( resource_expiration_delay_(expiration_delay), disallow_non_exact_reuse_(disallow_non_exact_reuse), tracing_id_(g_next_tracing_id.GetNext()), + flush_evicted_resources_deadline_(base::TimeTicks::Max()), + clock_(base::DefaultTickClock::GetInstance()), weak_ptr_factory_(this) { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "cc::ResourcePool", task_runner_.get()); @@ -300,34 +304,40 @@ void ResourcePool::OnResourceReleased(size_t unique_id, busy_resources_.erase(busy_it); } -void ResourcePool::PrepareForExport(const InUsePoolResource& resource) { +bool ResourcePool::PrepareForExport(const InUsePoolResource& in_use_resource) { + PoolResource* resource = in_use_resource.resource_; // Exactly one of gpu or software backing should exist. - DCHECK(resource.resource_->gpu_backing() || - resource.resource_->software_backing()); - DCHECK(!resource.resource_->gpu_backing() || - !resource.resource_->software_backing()); + DCHECK(resource->gpu_backing() || resource->software_backing()); + DCHECK(!resource->gpu_backing() || !resource->software_backing()); viz::TransferableResource transferable; - if (resource.resource_->gpu_backing()) { + if (resource->gpu_backing()) { + GpuBacking* gpu_backing = resource->gpu_backing(); + if (gpu_backing->mailbox.IsZero()) { + // This can happen if we failed to allocate a GpuMemoryBuffer. Avoid + // sending an invalid resource to the parent in that case, and avoid + // caching/reusing the resource. + resource->set_resource_id(0); + resource->mark_avoid_reuse(); + return false; + } transferable = viz::TransferableResource::MakeGLOverlay( - resource.resource_->gpu_backing()->mailbox, GL_LINEAR, - resource.resource_->gpu_backing()->texture_target, - resource.resource_->gpu_backing()->mailbox_sync_token, - resource.resource_->size(), - resource.resource_->gpu_backing()->overlay_candidate); - transferable.read_lock_fences_enabled = - resource.resource_->gpu_backing()->wait_on_fence_required; + 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; } else { transferable = viz::TransferableResource::MakeSoftware( - resource.resource_->software_backing()->shared_bitmap_id, - resource.resource_->size(), resource.resource_->format()); + resource->software_backing()->shared_bitmap_id, resource->size(), + resource->format()); } - transferable.format = resource.resource_->format(); - transferable.color_space = resource.resource_->color_space(); - resource.resource_->set_resource_id(resource_provider_->ImportResource( + transferable.format = resource->format(); + transferable.color_space = resource->color_space(); + resource->set_resource_id(resource_provider_->ImportResource( std::move(transferable), viz::SingleReleaseCallback::Create(base::BindOnce( &ResourcePool::OnResourceReleased, weak_ptr_factory_.GetWeakPtr(), - resource.resource_->unique_id())))); + resource->unique_id())))); + return true; } void ResourcePool::InvalidateResources() { @@ -380,7 +390,7 @@ void ResourcePool::ReleaseResource(InUsePoolResource in_use_resource) { // crbug.com/598286. CHECK(it->second.get()); - pool_resource->set_last_usage(base::TimeTicks::Now()); + pool_resource->set_last_usage(clock_->NowTicks()); in_use_memory_usage_bytes_ -= viz::ResourceSizes::UncheckedSizeInBytes<size_t>(pool_resource->size(), pool_resource->format()); @@ -458,6 +468,10 @@ void ResourcePool::DeleteResource(std::unique_ptr<PoolResource> resource) { resource->size(), resource->format()); total_memory_usage_bytes_ -= resource_bytes; --total_resource_count_; + if (flush_evicted_resources_deadline_ == base::TimeTicks::Max()) { + flush_evicted_resources_deadline_ = + clock_->NowTicks() + kDefaultMaxFlushDelay; + } } void ResourcePool::UpdateResourceContentIdAndInvalidation( @@ -493,26 +507,27 @@ void ResourcePool::ScheduleEvictExpiredResourcesIn( void ResourcePool::EvictExpiredResources() { evict_expired_resources_pending_ = false; - base::TimeTicks current_time = base::TimeTicks::Now(); + base::TimeTicks current_time = clock_->NowTicks(); EvictResourcesNotUsedSince(current_time - resource_expiration_delay_); - if (unused_resources_.empty()) { + if (unused_resources_.empty() || + flush_evicted_resources_deadline_ <= current_time) { // If nothing is evictable, we have deleted one (and possibly more) // resources without any new activity. Flush to ensure these deletions are // processed. - if (context_provider_) { - // Flush any ContextGL work as well as any SharedImageInterface work. - context_provider_->ContextGL()->OrderingBarrierCHROMIUM(); - context_provider_->ContextSupport()->FlushPendingWork(); - } - return; + FlushEvictedResources(); } - // If we still have evictable resources, schedule a call to - // EvictExpiredResources at the time when the LRU buffer expires. - ScheduleEvictExpiredResourcesIn(GetUsageTimeForLRUResource() + - resource_expiration_delay_ - current_time); + if (!unused_resources_.empty()) { + // If we still have evictable resources, schedule a call to + // EvictExpiredResources for either (a) the time when the LRU buffer expires + // or (b) the deadline to explicitly flush previously evicted resources. + ScheduleEvictExpiredResourcesIn( + std::min(GetUsageTimeForLRUResource() + resource_expiration_delay_, + flush_evicted_resources_deadline_) - + current_time); + } } void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) { @@ -538,6 +553,15 @@ base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const { return busy_resources_.back()->last_usage(); } +void ResourcePool::FlushEvictedResources() { + flush_evicted_resources_deadline_ = base::TimeTicks::Max(); + if (context_provider_) { + // Flush any ContextGL work as well as any SharedImageInterface work. + context_provider_->ContextGL()->OrderingBarrierCHROMIUM(); + context_provider_->ContextSupport()->FlushPendingWork(); + } +} + bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) { if (args.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) { @@ -572,6 +596,7 @@ void ResourcePool::OnMemoryPressure( break; case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: EvictResourcesNotUsedSince(base::TimeTicks() + base::TimeDelta::Max()); + FlushEvictedResources(); break; } } diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h index b7928fcae8c..cd72eb84b7c 100644 --- a/chromium/cc/resources/resource_pool.h +++ b/chromium/cc/resources/resource_pool.h @@ -16,6 +16,7 @@ #include "base/memory/memory_pressure_listener.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "base/time/tick_clock.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/memory_dump_provider.h" #include "base/unguessable_token.h" @@ -51,6 +52,9 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { // Delay before a resource is considered expired. static constexpr base::TimeDelta kDefaultExpirationDelay = base::TimeDelta::FromSeconds(5); + // Max delay before an evicted resource is flushed. + static constexpr base::TimeDelta kDefaultMaxFlushDelay = + base::TimeDelta::FromSeconds(1); // A base class to hold ownership of gpu backed PoolResources. Allows the // client to define destruction semantics. @@ -217,7 +221,10 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { // acquired InUsePoolResource will be only metadata, and the backing is given // to it by code which is aware of the expected backing type - currently by // RasterBufferProvider::AcquireBufferForRaster(). - void PrepareForExport(const InUsePoolResource& resource); + // Returns false if the backing does not contain valid data, in particular + // a zero mailbox for GpuBacking, in which case the resource is not exported, + // and true otherwise. + bool PrepareForExport(const InUsePoolResource& resource); // Marks any resources in the pool as invalid, preventing their reuse. Call if // previous resources were allocated in one way, but future resources should @@ -258,6 +265,9 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { return !disallow_non_exact_reuse_; } + // Overrides internal clock for testing purposes. + void SetClockForTesting(const base::TickClock* clock) { clock_ = clock; } + private: FRIEND_TEST_ALL_PREFIXES(ResourcePoolTest, ReuseResource); FRIEND_TEST_ALL_PREFIXES(ResourcePoolTest, ExactRequestsRespected); @@ -365,6 +375,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { void EvictResourcesNotUsedSince(base::TimeTicks time_limit); bool HasEvictableResources() const; base::TimeTicks GetUsageTimeForLRUResource() const; + void FlushEvictedResources(); viz::ClientResourceProvider* const resource_provider_; viz::ContextProvider* const context_provider_; @@ -391,6 +402,10 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; + base::TimeTicks flush_evicted_resources_deadline_; + + const base::TickClock* clock_; + base::WeakPtrFactory<ResourcePool> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ResourcePool); diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc index ef0ba34c2db..5f159541f0d 100644 --- a/chromium/cc/resources/resource_pool_unittest.cc +++ b/chromium/cc/resources/resource_pool_unittest.cc @@ -6,14 +6,16 @@ #include <stddef.h> -#include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/test_mock_time_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "components/viz/client/client_resource_provider.h" #include "components/viz/common/resources/resource_sizes.h" #include "components/viz/common/resources/returned_resource.h" #include "components/viz/test/test_context_provider.h" +#include "components/viz/test/test_context_support.h" #include "components/viz/test/test_shared_bitmap_manager.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -21,13 +23,17 @@ namespace cc { class ResourcePoolTest : public testing::Test { public: void SetUp() override { - context_provider_ = viz::TestContextProvider::Create(); + auto context_support = std::make_unique<MockContextSupport>(); + context_support_ = context_support.get(); + context_provider_ = + viz::TestContextProvider::Create(std::move(context_support)); context_provider_->BindToCurrentThread(); resource_provider_ = std::make_unique<viz::ClientResourceProvider>(true); - task_runner_ = base::ThreadTaskRunnerHandle::Get(); + test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); resource_pool_ = std::make_unique<ResourcePool>( - resource_provider_.get(), context_provider_.get(), task_runner_, + resource_provider_.get(), context_provider_.get(), test_task_runner_, ResourcePool::kDefaultExpirationDelay, false); + resource_pool_->SetClockForTesting(test_task_runner_->GetMockTickClock()); } void TearDown() override { @@ -35,6 +41,12 @@ class ResourcePoolTest : public testing::Test { } protected: + class MockContextSupport : public viz::TestContextSupport { + public: + MockContextSupport() = default; + MOCK_METHOD0(FlushPendingWork, void()); + }; + class StubGpuBacking : public ResourcePool::GpuBacking { public: void OnMemoryDump( @@ -46,6 +58,7 @@ class ResourcePoolTest : public testing::Test { void SetBackingOnResource(const ResourcePool::InUsePoolResource& resource) { auto backing = std::make_unique<StubGpuBacking>(); + backing->mailbox = gpu::Mailbox::Generate(); backing->mailbox_sync_token.Set( gpu::GPU_IO, gpu::CommandBufferId::FromUnsafeValue(1), 1); resource.set_gpu_backing(std::move(backing)); @@ -57,9 +70,10 @@ class ResourcePoolTest : public testing::Test { } viz::TestSharedBitmapManager shared_bitmap_manager_; + MockContextSupport* context_support_; scoped_refptr<viz::TestContextProvider> context_provider_; std::unique_ptr<viz::ClientResourceProvider> resource_provider_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_; std::unique_ptr<ResourcePool> resource_pool_; }; @@ -76,6 +90,67 @@ TEST_F(ResourcePoolTest, AcquireRelease) { resource_pool_->ReleaseResource(std::move(resource)); } +TEST_F(ResourcePoolTest, EventuallyEvictAndFlush) { + gfx::Size size(100, 100); + viz::ResourceFormat format = viz::RGBA_8888; + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + ResourcePool::InUsePoolResource resource = + resource_pool_->AcquireResource(size, format, color_space); + resource_pool_->ReleaseResource(std::move(resource)); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + + // Expect flush after eviction and flush delay. + EXPECT_CALL(*context_support_, FlushPendingWork()).Times(testing::AtLeast(1)); + test_task_runner_->FastForwardBy(ResourcePool::kDefaultExpirationDelay + + ResourcePool::kDefaultMaxFlushDelay); + EXPECT_EQ(0u, resource_pool_->GetTotalResourceCountForTesting()); +} + +TEST_F(ResourcePoolTest, FlushEvenIfMoreUnusedToEvict) { + gfx::Size size(100, 100); + viz::ResourceFormat format = viz::RGBA_8888; + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + ResourcePool::InUsePoolResource resource1 = + resource_pool_->AcquireResource(size, format, color_space); + ResourcePool::InUsePoolResource resource2 = + resource_pool_->AcquireResource(size, format, color_space); + + // Time 0: No resources evicted yet. + EXPECT_EQ(2u, resource_pool_->GetTotalResourceCountForTesting()); + + // Space the resource last_usage out so that they don't expire at the same + // time. resource1 last used at time 0 (expires kDefaultExpirationDelay) and + // resource2 last used at last_usage_gap (expires kDefaultExpireationDelay + + // last_usage_gap). + const base::TimeDelta last_usage_gap = + ResourcePool::kDefaultMaxFlushDelay * 2; + resource_pool_->ReleaseResource(std::move(resource1)); + test_task_runner_->FastForwardBy(last_usage_gap); + resource_pool_->ReleaseResource(std::move(resource2)); + + // Time |last_usage_gap|: No resources evicted yet. + EXPECT_EQ(2u, resource_pool_->GetTotalResourceCountForTesting()); + + // Time |kDefaultExpirationDelay|: resource1 evicted, but not resource2 yet. + test_task_runner_->FastForwardBy(ResourcePool::kDefaultExpirationDelay - + last_usage_gap); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + + // Expect at least one flush kDefaultMaxFlushDelay after an eviction. + EXPECT_CALL(*context_support_, FlushPendingWork()).Times(testing::AtLeast(1)); + test_task_runner_->FastForwardBy(ResourcePool::kDefaultMaxFlushDelay); + + // Time |kDefaultExpirationDelay + kDefaultMaxFlushDelay|: + // Check that flush was called and resource2 still not evicted. + testing::Mock::VerifyAndClearExpectations(context_support_); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + + // Wait a long time and resource2 should get evicted and flushed. + EXPECT_CALL(*context_support_, FlushPendingWork()).Times(testing::AtLeast(1)); + test_task_runner_->FastForwardBy(ResourcePool::kDefaultExpirationDelay * 100); + EXPECT_EQ(0u, resource_pool_->GetTotalResourceCountForTesting()); +} + TEST_F(ResourcePoolTest, AccountingSingleResource) { // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; @@ -165,7 +240,7 @@ TEST_F(ResourcePoolTest, LostResource) { resource_pool_->AcquireResource(size, format, color_space); SetBackingOnResource(resource); - resource_pool_->PrepareForExport(resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(resource)); std::vector<viz::ResourceId> export_ids = {resource.resource_id_for_export()}; std::vector<viz::TransferableResource> transferable_resources; @@ -183,12 +258,6 @@ TEST_F(ResourcePoolTest, LostResource) { } TEST_F(ResourcePoolTest, BusyResourcesNotFreed) { - // Set a quick resource expiration delay so that this test doesn't take long - // to run. - resource_pool_ = std::make_unique<ResourcePool>( - resource_provider_.get(), context_provider_.get(), task_runner_, - base::TimeDelta::FromMilliseconds(10), false); - // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; size_t count_limit = 100; @@ -204,7 +273,7 @@ TEST_F(ResourcePoolTest, BusyResourcesNotFreed) { EXPECT_EQ(1u, resource_pool_->resource_count()); SetBackingOnResource(resource); - resource_pool_->PrepareForExport(resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(resource)); std::vector<viz::TransferableResource> transfers; resource_provider_->PrepareSendToParent({resource.resource_id_for_export()}, @@ -215,12 +284,9 @@ TEST_F(ResourcePoolTest, BusyResourcesNotFreed) { EXPECT_EQ(0u, resource_pool_->memory_usage_bytes()); EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting()); - // Wait for our resource pool to evict resources. We expect resources to be - // released within 10 ms, give the thread up to 200. - base::RunLoop run_loop; - task_runner_->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), - base::TimeDelta::FromMillisecondsD(200)); - run_loop.Run(); + // Wait for our resource pool to evict resources. Wait 10x the expiration + // delay. + test_task_runner_->FastForwardBy(ResourcePool::kDefaultExpirationDelay * 10); // Busy resources are still held, since they may be in flight to the display // compositor and should not be freed. @@ -230,12 +296,6 @@ TEST_F(ResourcePoolTest, BusyResourcesNotFreed) { } TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) { - // Set a quick resource expiration delay so that this test doesn't take long - // to run. - resource_pool_ = std::make_unique<ResourcePool>( - resource_provider_.get(), context_provider_.get(), task_runner_, - base::TimeDelta::FromMilliseconds(100), false); - // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; size_t count_limit = 100; @@ -254,7 +314,7 @@ TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) { // Export the resource to the display compositor. SetBackingOnResource(resource); - resource_pool_->PrepareForExport(resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(resource)); std::vector<viz::TransferableResource> transfers; resource_provider_->PrepareSendToParent({resource.resource_id_for_export()}, &transfers, context_provider_.get()); @@ -273,12 +333,9 @@ TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) { EXPECT_EQ(0u, resource_pool_->resource_count()); EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); - // Wait for our resource pool to evict resources. We expect resources to be - // released within 100 ms, give the thread up to 200. - base::RunLoop run_loop; - task_runner_->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), - base::TimeDelta::FromMillisecondsD(200)); - run_loop.Run(); + // Wait for our resource pool to evict resources. Wait 10x the expiration + // delay. + test_task_runner_->FastForwardBy(ResourcePool::kDefaultExpirationDelay * 10); EXPECT_EQ(0u, resource_pool_->GetTotalMemoryUsageForTesting()); } @@ -463,7 +520,7 @@ TEST_F(ResourcePoolTest, PurgedMemory) { ResourcePool::InUsePoolResource resource = resource_pool_->AcquireResource(size, format, color_space); SetBackingOnResource(resource); - resource_pool_->PrepareForExport(resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(resource)); EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); @@ -516,7 +573,7 @@ TEST_F(ResourcePoolTest, InvalidateResources) { ResourcePool::InUsePoolResource busy_resource = resource_pool_->AcquireResource(size, format, color_space); SetBackingOnResource(busy_resource); - resource_pool_->PrepareForExport(busy_resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(busy_resource)); EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); EXPECT_EQ(1u, resource_pool_->resource_count()); @@ -582,8 +639,8 @@ TEST_F(ResourcePoolTest, ExactRequestsRespected) { gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); resource_pool_ = std::make_unique<ResourcePool>( - resource_provider_.get(), context_provider_.get(), task_runner_, - base::TimeDelta::FromMilliseconds(100), true); + resource_provider_.get(), context_provider_.get(), test_task_runner_, + ResourcePool::kDefaultExpirationDelay, true); // Create unused resource with size 100x100. CheckAndReturnResource(resource_pool_->AcquireResource(gfx::Size(100, 100), @@ -635,7 +692,7 @@ TEST_F(ResourcePoolTest, MetadataSentToDisplayCompositor) { resource.gpu_backing()->wait_on_fence_required = true; resource.gpu_backing()->overlay_candidate = true; - resource_pool_->PrepareForExport(resource); + EXPECT_TRUE(resource_pool_->PrepareForExport(resource)); std::vector<viz::TransferableResource> transfer; resource_provider_->PrepareSendToParent({resource.resource_id_for_export()}, @@ -657,4 +714,37 @@ TEST_F(ResourcePoolTest, MetadataSentToDisplayCompositor) { resource_pool_->ReleaseResource(std::move(resource)); } +TEST_F(ResourcePoolTest, InvalidResource) { + // Limits high enough to not be hit by this test. + size_t bytes_limit = 10 * 1024 * 1024; + size_t count_limit = 100; + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); + + // These values are all non-default values so we can tell they are propagated. + gfx::Size size(100, 101); + viz::ResourceFormat format = viz::RGBA_4444; + EXPECT_NE(gfx::BufferFormat::RGBA_8888, viz::BufferFormat(format)); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + uint32_t target = 5; + + ResourcePool::InUsePoolResource resource = + resource_pool_->AcquireResource(size, format, color_space); + + // Keep a zero mailbox + auto backing = std::make_unique<StubGpuBacking>(); + backing->texture_target = target; + backing->wait_on_fence_required = true; + backing->overlay_candidate = true; + resource.set_gpu_backing(std::move(backing)); + + EXPECT_FALSE(resource_pool_->PrepareForExport(resource)); + + resource_pool_->ReleaseResource(std::move(resource)); + + // Acquire another resource. The resource should not be reused. + resource = resource_pool_->AcquireResource(size, format, color_space); + EXPECT_FALSE(resource.gpu_backing()); + resource_pool_->ReleaseResource(std::move(resource)); +} + } // namespace cc diff --git a/chromium/cc/scheduler/begin_frame_tracker.h b/chromium/cc/scheduler/begin_frame_tracker.h index 33d124ad7e5..e80f7383768 100644 --- a/chromium/cc/scheduler/begin_frame_tracker.h +++ b/chromium/cc/scheduler/begin_frame_tracker.h @@ -10,7 +10,7 @@ #include "base/location.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/cc_export.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index fcdbde8a7c0..e930243b08e 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -10,7 +10,7 @@ #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/devtools_instrumentation.h" #include "cc/scheduler/compositor_timing_history.h" #include "components/viz/common/frame_sinks/delay_based_time_source.h" @@ -258,6 +258,7 @@ void Scheduler::StartOrStopBeginFrames() { BeginImplFrameNotExpectedSoon(); devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_, false); + client_->WillNotReceiveBeginFrame(); } } @@ -306,6 +307,16 @@ void Scheduler::OnBeginFrameSourcePausedChanged(bool paused) { bool Scheduler::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) { TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue()); + // If the begin frame interval is different than last frame and bigger than + // zero then let |client_| know about the new interval for animations. In + // theory the interval should always be bigger than zero but the value is + // provided by APIs outside our control. + if (args.interval != last_frame_interval_ && + args.interval > base::TimeDelta()) { + last_frame_interval_ = args.interval; + client_->FrameIntervalUpdated(last_frame_interval_); + } + if (ShouldDropBeginFrame(args)) { TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped", TRACE_EVENT_SCOPE_THREAD); @@ -729,10 +740,10 @@ void Scheduler::DrawForced() { client_->CurrentFrameHadRAF(), client_->NextFrameHasPendingRAF()); } -void Scheduler::SetDeferCommits(bool defer_commits) { - TRACE_EVENT1("cc", "Scheduler::SetDeferCommits", "defer_commits", - defer_commits); - state_machine_.SetDeferCommits(defer_commits); +void Scheduler::SetDeferMainFrameUpdate(bool defer_main_frame_update) { + TRACE_EVENT1("cc", "Scheduler::SetDeferMainFrameUpdate", + "defer_main_frame_update", defer_main_frame_update); + state_machine_.SetDeferMainFrameUpdate(defer_main_frame_update); ProcessScheduledActions(); } diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h index d042ec39883..06c32386641 100644 --- a/chromium/cc/scheduler/scheduler.h +++ b/chromium/cc/scheduler/scheduler.h @@ -40,6 +40,12 @@ class SchedulerClient { const viz::BeginFrameArgs& args) = 0; virtual DrawResult ScheduledActionDrawIfPossible() = 0; virtual DrawResult ScheduledActionDrawForced() = 0; + + // The Commit step occurs when the client received the BeginFrame from the + // source and we perform at most one commit per BeginFrame. In this step the + // main thread collects all updates then blocks and gives control to the + // 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 ScheduledActionActivateSyncTree() = 0; virtual void ScheduledActionBeginLayerTreeFrameSinkCreation() = 0; @@ -49,11 +55,13 @@ class SchedulerClient { virtual void ScheduledActionPerformImplSideInvalidation() = 0; virtual void DidFinishImplFrame() = 0; virtual void DidNotProduceFrame(const viz::BeginFrameAck& ack) = 0; + virtual void WillNotReceiveBeginFrame() = 0; virtual void SendBeginMainFrameNotExpectedSoon() = 0; virtual void ScheduledActionBeginMainFrameNotExpectedUntil( base::TimeTicks time) = 0; + virtual void FrameIntervalUpdated(base::TimeDelta interval) = 0; - // Functions used for reporting anmation targeting UMA, crbug.com/758439. + // Functions used for reporting animation targeting UMA, crbug.com/758439. virtual size_t CompositedAnimationsCount() const = 0; virtual size_t MainThreadAnimationsCount() const = 0; virtual bool CurrentFrameHadRAF() const = 0; @@ -88,10 +96,19 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { void SetVisible(bool visible); bool visible() { return state_machine_.visible(); } void SetCanDraw(bool can_draw); + + // We have 2 copies of the layer trees on the compositor thread: pending_tree + // and active_tree. When we finish asynchronously rastering all tiles on + // 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(); void NotifyReadyToDraw(); void SetBeginFrameSource(viz::BeginFrameSource* source); + // Set |needs_begin_main_frame_| to true, which will cause the BeginFrame + // source to be told to send BeginFrames to this client so that this client + // can send a CompositorFrame to the display compositor with appropriate + // timing. void SetNeedsBeginMainFrame(); // Requests a single impl frame (after the current frame if there is one // active). @@ -123,12 +140,24 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { void SetTreePrioritiesAndScrollState(TreePriority tree_priority, ScrollHandlerState scroll_handler_state); + // Commit step happens after the main thread has completed updating for a + // BeginMainFrame request from the compositor, and blocks the main thread + // to copy the layer tree to the compositor thread. Call this method when the + // main thread updates are completed to signal it is ready for the commmit. void NotifyReadyToCommit(); 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 + // dedicated thread. + // |WillPrepareTiles| is called before PrepareTiles step to have the scheduler + // track when PrepareTiles starts. void WillPrepareTiles(); + // |DidPrepareTiles| is called after PrepareTiles step to have the scheduler + // track how long PrepareTiles takes. void DidPrepareTiles(); + void DidLoseLayerTreeFrameSink(); void DidCreateAndInitializeLayerTreeFrameSink(); @@ -156,7 +185,9 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { base::TimeTicks LastBeginImplFrameTime(); - void SetDeferCommits(bool defer_commits); + // Deferring BeginMainFrame prevents all document lifecycle updates, and + // compositor commits. + void SetDeferMainFrameUpdate(bool defer_main_frame_update); // Controls whether the BeginMainFrameNotExpected messages should be sent to // the main thread by the cc scheduler. @@ -223,6 +254,10 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { bool stopped_ = false; + // Keeps track of the begin frame interval from the last BeginFrameArgs to + // arrive so that |client_| can be informed about changes. + base::TimeDelta last_frame_interval_; + private: // Posts the deadline task if needed by checking // SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode(). This only diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc index de38d19ab87..9e488fc8725 100644 --- a/chromium/cc/scheduler/scheduler_settings.cc +++ b/chromium/cc/scheduler/scheduler_settings.cc @@ -4,7 +4,7 @@ #include "cc/scheduler/scheduler_settings.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" namespace cc { diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index d9711b24a86..57bd80ed57e 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -7,7 +7,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" namespace cc { @@ -223,7 +223,7 @@ void SchedulerStateMachine::AsValueInto( state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency", skip_next_begin_main_frame_to_reduce_latency_); state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_); - state->SetBoolean("defer_commits", defer_commits_); + state->SetBoolean("defer_main_frame_update", defer_main_frame_update_); state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_); state->SetBoolean("did_draw_in_last_frame", did_draw_in_last_frame_); state->SetBoolean("did_submit_in_last_frame", did_submit_in_last_frame_); @@ -431,7 +431,7 @@ bool SchedulerStateMachine::CouldSendBeginMainFrame() const { return false; // Do not make a new commits when it is deferred. - if (defer_commits_) + if (defer_main_frame_update_) return false; return true; @@ -714,8 +714,12 @@ bool SchedulerStateMachine::CouldCreatePendingTree() const { if (begin_frame_source_paused_) return false; - // Don't create a pending tree till a frame sink is initialized. - if (!HasInitializedLayerTreeFrameSink()) + // Don't create a pending tree till a frame sink is fully initialized. Check + // for the ACTIVE state explicitly instead of calling + // HasInitializedLayerTreeFrameSink() because that only checks if frame sink + // has been recreated, but doesn't check if we're waiting for first commit or + // activation. + if (layer_tree_frame_sink_state_ != LayerTreeFrameSinkState::ACTIVE) return false; return true; @@ -959,8 +963,9 @@ void SchedulerStateMachine::SetVideoNeedsBeginFrames( video_needs_begin_frames_ = video_needs_begin_frames; } -void SchedulerStateMachine::SetDeferCommits(bool defer_commits) { - defer_commits_ = defer_commits; +void SchedulerStateMachine::SetDeferMainFrameUpdate( + bool defer_main_frame_update) { + defer_main_frame_update_ = defer_main_frame_update; } // These are the cases where we require a BeginFrame message to make progress @@ -972,7 +977,7 @@ bool SchedulerStateMachine::BeginFrameRequiredForAction() const { return true; return needs_redraw_ || needs_one_begin_impl_frame_ || - (needs_begin_main_frame_ && !defer_commits_) || + (needs_begin_main_frame_ && !defer_main_frame_update_) || needs_impl_side_invalidation_; } @@ -992,7 +997,8 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { // request frames when commits are disabled, because the frame requests will // not provide the needed commit (and will wake up the process when it could // stay idle). - if ((begin_main_frame_state_ != BeginMainFrameState::IDLE) && !defer_commits_) + if ((begin_main_frame_state_ != BeginMainFrameState::IDLE) && + !defer_main_frame_update_) return true; // If the pending tree activates quickly, we'll want a BeginImplFrame soon @@ -1155,9 +1161,10 @@ bool SchedulerStateMachine::ShouldBlockDeadlineIndefinitely() const { // Wait for main frame to be ready for commits if in full-pipe mode, so that // we ensure we block during renderer initialization. In commit_to_active_tree - // mode, we cannot block for defer_commits_, as this may negatively affect - // animation smoothness during resize or orientation changes. - if (defer_commits_ && settings_.wait_for_all_pipeline_stages_before_draw) + // mode, we cannot block for defer_main_frame_update_, as this may negatively + // affect animation smoothness during resize or orientation changes. + if (defer_main_frame_update_ && + settings_.wait_for_all_pipeline_stages_before_draw) return true; // Wait for main frame if one is in progress or about to be started. diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h index bc1e83d472a..b3d2eea0d06 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.h +++ b/chromium/cc/scheduler/scheduler_state_machine.h @@ -295,7 +295,7 @@ class CC_EXPORT SchedulerStateMachine { bool CouldSendBeginMainFrame() const; - void SetDeferCommits(bool defer_commits); + void SetDeferMainFrameUpdate(bool defer_main_frame_update); void SetVideoNeedsBeginFrames(bool video_needs_begin_frames); bool video_needs_begin_frames() const { return video_needs_begin_frames_; } @@ -417,7 +417,7 @@ class CC_EXPORT SchedulerStateMachine { bool critical_begin_main_frame_to_activate_is_fast_ = true; bool main_thread_missed_last_deadline_ = false; bool skip_next_begin_main_frame_to_reduce_latency_ = false; - bool defer_commits_ = false; + bool defer_main_frame_update_ = false; bool video_needs_begin_frames_ = false; bool last_commit_had_no_updates_ = false; bool active_tree_is_ready_to_draw_ = true; diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index aa742f8a8a2..ca5ad89c12c 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -270,7 +270,7 @@ TEST(SchedulerStateMachineTest, BeginFrameNeeded) { state.SetNeedsRedraw(false); state.SetNeedsOneBeginImplFrame(false); state.SetNeedsBeginMainFrameForTest(true); - state.SetDeferCommits(true); + state.SetDeferMainFrameUpdate(true); EXPECT_FALSE(state.BeginFrameNeeded()); } @@ -1188,7 +1188,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); // When commits are deferred, we don't block the deadline. - state.SetDeferCommits(true); + state.SetDeferMainFrameUpdate(true); state.OnBeginImplFrame(0, 13, kAnimateOnly); EXPECT_NE(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED, state.CurrentBeginImplFrameDeadlineMode()); @@ -2106,7 +2106,7 @@ TEST(SchedulerStateMachineTest, TestDeferCommit) { StateMachine state(settings); SET_UP_STATE(state) - state.SetDeferCommits(true); + state.SetDeferMainFrameUpdate(true); state.SetNeedsBeginMainFrame(); EXPECT_FALSE(state.BeginFrameNeeded()); @@ -2118,7 +2118,7 @@ TEST(SchedulerStateMachineTest, TestDeferCommit) { state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); - state.SetDeferCommits(false); + state.SetDeferMainFrameUpdate(false); state.IssueNextBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); @@ -2310,24 +2310,63 @@ TEST(SchedulerStateMachineTest, SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION); } -TEST(SchedulerStateMachineTest, - NoImplSideInvalidationWithoutLayerTreeFrameSink) { +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); - // Impl-side invalidations should not be triggered till the frame sink is - // initialized. state.DidLoseLayerTreeFrameSink(); + + // Create new frame sink but don't commit or activate yet. EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); - // No impl-side invalidations should be performed during frame sink creation. + state.DidCreateAndInitializeLayerTreeFrameSink(); + state.SetNeedsBeginMainFrame(); + bool needs_first_draw_on_activation = true; state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); + + state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); + // No impl side invalidation because we're still waiting for first commit. + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); + + state.NotifyBeginMainFrameStarted(); + state.NotifyReadyToCommit(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT); + + state.OnBeginImplFrameDeadline(); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); + + state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); + state.IssueNextBeginImplFrame(); + // No impl side invalidation because we're still waiting for first activation. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); + + state.NotifyReadyToActivate(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); + + state.OnBeginImplFrameDeadline(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE); + state.OnBeginImplFrameIdle(); + + state.SetNeedsBeginMainFrame(); + state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation); + + state.IssueNextBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); + // Impl side invalidation only after receiving first commit and activation for + // new frame sink. + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION); } TEST(SchedulerStateMachineTest, ImplSideInvalidationWhenPendingTreeExists) { @@ -2504,10 +2543,10 @@ TEST(SchedulerStateMachineTest, TestFullPipelineMode) { state.CurrentBeginImplFrameDeadlineMode()); // Even if main thread defers commits, we still need to wait for it. - state.SetDeferCommits(true); + state.SetDeferMainFrameUpdate(true); EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED, state.CurrentBeginImplFrameDeadlineMode()); - state.SetDeferCommits(false); + state.SetDeferMainFrameUpdate(false); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME); diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index aff1c76351c..715ecc43ca0 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -73,6 +73,8 @@ class FakeSchedulerClient : public SchedulerClient, return posted_begin_impl_frame_deadline_; } + base::TimeDelta frame_interval() const { return frame_interval_; } + int ActionIndex(const char* action) const { for (size_t i = 0; i < actions_.size(); i++) if (!strcmp(actions_[i], action)) @@ -128,6 +130,8 @@ class FakeSchedulerClient : public SchedulerClient, last_begin_frame_ack_ = ack; } + void WillNotReceiveBeginFrame() override {} + void ScheduledActionSendBeginMainFrame( const viz::BeginFrameArgs& args) override { EXPECT_FALSE(inside_action_); @@ -135,6 +139,9 @@ class FakeSchedulerClient : public SchedulerClient, PushAction("ScheduledActionSendBeginMainFrame"); last_begin_main_frame_args_ = args; } + void FrameIntervalUpdated(base::TimeDelta interval) override { + frame_interval_ = interval; + } const viz::BeginFrameArgs& last_begin_main_frame_args() { return last_begin_main_frame_args_; @@ -275,6 +282,7 @@ class FakeSchedulerClient : public SchedulerClient, std::vector<std::unique_ptr<base::trace_event::ConvertableToTraceFormat>> states_; TestScheduler* scheduler_ = nullptr; + base::TimeDelta frame_interval_; }; enum BeginFrameSourceType { @@ -692,7 +700,7 @@ TEST_F(SchedulerTest, RequestCommit) { TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) { SetUpScheduler(EXTERNAL_BFS); - scheduler_->SetDeferCommits(true); + scheduler_->SetDeferMainFrameUpdate(true); scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(); @@ -704,7 +712,7 @@ TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) { EXPECT_FALSE(scheduler_->begin_frames_expected()); client_->Reset(); - scheduler_->SetDeferCommits(false); + scheduler_->SetDeferMainFrameUpdate(false); EXPECT_ACTIONS("AddObserver(this)"); // Start new BeginMainFrame after defer commit is off. @@ -717,13 +725,13 @@ TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) { TEST_F(SchedulerTest, DeferCommitWithRedraw) { SetUpScheduler(EXTERNAL_BFS); - scheduler_->SetDeferCommits(true); + scheduler_->SetDeferMainFrameUpdate(true); scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(); - // The SetNeedsRedraw will override the SetDeferCommits(true), to allow a - // begin frame to be needed. + // The SetNeedsRedraw will override the SetDeferMainFrameUpdate(true), to + // allow a begin frame to be needed. client_->Reset(); scheduler_->SetNeedsRedraw(); EXPECT_ACTIONS("AddObserver(this)"); @@ -1492,6 +1500,63 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginFrame) { "ScheduledActionDrawIfPossible"); } +TEST_F(SchedulerTest, FrameIntervalUpdated) { + // Verify that the SchedulerClient gets updates when the begin frame interval + // changes. + SetUpScheduler(EXTERNAL_BFS); + constexpr uint64_t kSourceId = viz::BeginFrameArgs::kStartingSourceId; + uint64_t sequence_number = viz::BeginFrameArgs::kStartingFrameNumber; + + base::TimeDelta interval = base::TimeDelta::FromMicroseconds( + base::Time::kMicrosecondsPerSecond / 120.0); + + // Send BeginFrameArgs with 120hz refresh rate and confirm client gets update. + scheduler_->SetNeedsRedraw(); + task_runner_->AdvanceMockTickClock(interval); + viz::BeginFrameArgs args1 = viz::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, + task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval, + viz::BeginFrameArgs::NORMAL); + fake_external_begin_frame_source_->TestOnBeginFrame(args1); + EXPECT_EQ(client_->frame_interval(), interval); + + // Send another BeginFrameArgs with 120hz refresh rate that arrives late. Even + // though the interval between begin frames arriving is bigger than |interval| + // the client only hears the interval specified in BeginFrameArgs. + scheduler_->SetNeedsRedraw(); + const base::TimeDelta late_delta = base::TimeDelta::FromMilliseconds(4); + task_runner_->AdvanceMockTickClock(interval + late_delta); + viz::BeginFrameArgs args2 = viz::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args1.deadline, + args1.deadline + interval, interval, viz::BeginFrameArgs::NORMAL); + fake_external_begin_frame_source_->TestOnBeginFrame(args2); + EXPECT_EQ(client_->frame_interval(), interval); + + // Change the interval for 90hz refresh rate. + interval = base::TimeDelta::FromMicroseconds( + base::Time::kMicrosecondsPerSecond / 90.0); + + // Send BeginFrameArgs with 90hz refresh rate and confirm client gets update. + scheduler_->SetNeedsRedraw(); + task_runner_->AdvanceMockTickClock(args2.deadline - task_runner_->NowTicks()); + viz::BeginFrameArgs args3 = viz::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args2.deadline, + args2.deadline + interval, interval, viz::BeginFrameArgs::NORMAL); + fake_external_begin_frame_source_->TestOnBeginFrame(args3); + EXPECT_EQ(client_->frame_interval(), interval); + + // Send BeginFrameArgs with zero interval. This isn't a valid interval and + // client shouldn't find out about it. + scheduler_->SetNeedsRedraw(); + task_runner_->AdvanceMockTickClock(interval); + viz::BeginFrameArgs args4 = viz::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args3.deadline, + args3.deadline + interval, base::TimeDelta(), + viz::BeginFrameArgs::NORMAL); + fake_external_begin_frame_source_->TestOnBeginFrame(args4); + EXPECT_EQ(client_->frame_interval(), interval); +} + TEST_F(SchedulerTest, MainFrameSkippedAfterLateCommit) { SetUpScheduler(EXTERNAL_BFS); fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration); @@ -3947,7 +4012,7 @@ TEST_F(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) { EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation"); client_->Reset(); scheduler_->DidCreateAndInitializeLayerTreeFrameSink(); - scheduler_->SetDeferCommits(true); + scheduler_->SetDeferMainFrameUpdate(true); scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(scheduler_->begin_frames_expected()); EXPECT_FALSE(client_->IsInsideBeginImplFrame()); diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc index 33385afc182..ce854bc73a1 100644 --- a/chromium/cc/tiles/checker_image_tracker.cc +++ b/chromium/cc/tiles/checker_image_tracker.cc @@ -387,7 +387,6 @@ void CheckerImageTracker::UpdateDecodeState(const DrawImage& draw_image, std::max(decode_state->scale.fHeight, draw_image.scale().fHeight)); decode_state->filter_quality = std::max(decode_state->filter_quality, draw_image.filter_quality()); - decode_state->color_space = draw_image.target_color_space(); decode_state->frame_index = draw_image.frame_index(); } @@ -427,7 +426,7 @@ void CheckerImageTracker::ScheduleNextImageDecode() { it->second.filter_quality, SkMatrix::MakeScale(it->second.scale.width(), it->second.scale.height()), - it->second.frame_index, it->second.color_space); + it->second.frame_index); outstanding_image_decode_.emplace(candidate); break; } diff --git a/chromium/cc/tiles/checker_image_tracker.h b/chromium/cc/tiles/checker_image_tracker.h index a8f850eb5cf..1a8229feaf5 100644 --- a/chromium/cc/tiles/checker_image_tracker.h +++ b/chromium/cc/tiles/checker_image_tracker.h @@ -136,7 +136,6 @@ class CC_EXPORT CheckerImageTracker { DecodePolicy policy = DecodePolicy::SYNC; SkFilterQuality filter_quality = kNone_SkFilterQuality; SkSize scale = SkSize::MakeEmpty(); - gfx::ColorSpace color_space; size_t frame_index = PaintImage::kDefaultFrameIndex; }; diff --git a/chromium/cc/tiles/checker_image_tracker_unittest.cc b/chromium/cc/tiles/checker_image_tracker_unittest.cc index 88c3f10cdd6..c375a591363 100644 --- a/chromium/cc/tiles/checker_image_tracker_unittest.cc +++ b/chromium/cc/tiles/checker_image_tracker_unittest.cc @@ -125,7 +125,7 @@ class CheckerImageTrackerTest : public testing::Test, .TakePaintImage(), SkIRect::MakeWH(dimension, dimension), kNone_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex, gfx::ColorSpace()); + PaintImage::kDefaultFrameIndex); } bool ShouldCheckerImage(const DrawImage& draw_image, WhichTree tree) { @@ -433,8 +433,7 @@ TEST_F(CheckerImageTrackerTest, CheckersOnlyStaticCompletedImages) { .set_paint_image_generator(CreatePaintImageGenerator(image_size)) .TakePaintImage(), SkIRect::MakeWH(image_size.width(), image_size.height()), - kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex, - gfx::ColorSpace()); + kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex); EXPECT_FALSE( ShouldCheckerImage(completed_paint_image, WhichTree::PENDING_TREE)); } @@ -461,12 +460,10 @@ TEST_F(CheckerImageTrackerTest, ChoosesMaxScaleAndQuality) { SetUpTracker(true); DrawImage image = CreateImage(ImageType::CHECKERABLE); - DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex, - gfx::ColorSpace()); + DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex); DrawImage scaled_image2 = DrawImage(image.paint_image(), image.src_rect(), kHigh_SkFilterQuality, - SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex, - gfx::ColorSpace()); + SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex); std::vector<DrawImage> draw_images = {scaled_image1, scaled_image2}; CheckerImageTracker::ImageDecodeQueue image_decode_queue = @@ -541,7 +538,7 @@ TEST_F(CheckerImageTrackerTest, UseSrcRectForSize) { DrawImage image = CreateImage(ImageType::CHECKERABLE); image = DrawImage(image.paint_image(), SkIRect::MakeWH(200, 200), image.filter_quality(), SkMatrix::I(), - PaintImage::kDefaultFrameIndex, image.target_color_space()); + PaintImage::kDefaultFrameIndex); EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE)); } diff --git a/chromium/cc/tiles/decoded_image_tracker.cc b/chromium/cc/tiles/decoded_image_tracker.cc index 9f717c9fc2a..ad1b297cfd7 100644 --- a/chromium/cc/tiles/decoded_image_tracker.cc +++ b/chromium/cc/tiles/decoded_image_tracker.cc @@ -38,7 +38,6 @@ DecodedImageTracker::~DecodedImageTracker() { void DecodedImageTracker::QueueImageDecode( const PaintImage& image, - const gfx::ColorSpace& target_color_space, const base::Callback<void(bool)>& callback) { size_t frame_index = PaintImage::kDefaultFrameIndex; TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), @@ -49,7 +48,7 @@ void DecodedImageTracker::QueueImageDecode( // our own. auto image_bounds = SkIRect::MakeWH(image.width(), image.height()); DrawImage draw_image(image, image_bounds, kNone_SkFilterQuality, - SkMatrix::I(), frame_index, target_color_space); + SkMatrix::I(), frame_index); image_controller_->QueueImageDecode( draw_image, base::Bind(&DecodedImageTracker::ImageDecodeFinished, diff --git a/chromium/cc/tiles/decoded_image_tracker.h b/chromium/cc/tiles/decoded_image_tracker.h index 36f6dc35820..e16b614e48d 100644 --- a/chromium/cc/tiles/decoded_image_tracker.h +++ b/chromium/cc/tiles/decoded_image_tracker.h @@ -34,7 +34,6 @@ class CC_EXPORT DecodedImageTracker { // completion. The callback takes a bool indicating whether the decode was // successful or not. void QueueImageDecode(const PaintImage& image, - const gfx::ColorSpace& target_color_space, const base::Callback<void(bool)>& callback); // Unlock all locked images - used to respond to memory pressure or diff --git a/chromium/cc/tiles/decoded_image_tracker_unittest.cc b/chromium/cc/tiles/decoded_image_tracker_unittest.cc index a31f5a2828b..4049261893f 100644 --- a/chromium/cc/tiles/decoded_image_tracker_unittest.cc +++ b/chromium/cc/tiles/decoded_image_tracker_unittest.cc @@ -86,44 +86,18 @@ class DecodedImageTrackerTest : public testing::Test { TEST_F(DecodedImageTrackerTest, QueueImageLocksImages) { bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), + CreateDiscardablePaintImage(gfx::Size(1, 1)), base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); EXPECT_EQ(1u, image_controller()->num_locked_images()); } -TEST_F(DecodedImageTrackerTest, Colorspace) { - bool locked = false; - gfx::ColorSpace decoded_color_space( - gfx::ColorSpace::PrimaryID::XYZ_D50, - gfx::ColorSpace::TransferID::IEC61966_2_1); - gfx::ColorSpace srgb_color_space = gfx::ColorSpace::CreateSRGB(); - auto paint_image = CreateDiscardablePaintImage(gfx::Size(1, 1)); - decoded_image_tracker()->QueueImageDecode( - paint_image, decoded_color_space, - base::Bind([](bool* locked, bool success) { *locked = true; }, - base::Unretained(&locked))); - - // Check that the decoded color space images are locked, but if the color - // space differs then that image is not locked. Note that we use the high - // filter quality here, since it shouldn't matter and the checks should - // succeed anyway. - DrawImage locked_draw_image( - paint_image, SkIRect::MakeWH(1, 1), kHigh_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex, decoded_color_space); - EXPECT_TRUE(image_controller()->IsDrawImageLocked(locked_draw_image)); - DrawImage srgb_draw_image(paint_image, SkIRect::MakeWH(1, 1), - kHigh_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex, srgb_color_space); - EXPECT_FALSE(image_controller()->IsDrawImageLocked(srgb_draw_image)); -} - TEST_F(DecodedImageTrackerTest, ImagesTimeOut) { // Add an image, this will start a 250ms timeout to release it. bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), + CreateDiscardablePaintImage(gfx::Size(1, 1)), base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -135,7 +109,7 @@ TEST_F(DecodedImageTrackerTest, ImagesTimeOut) { // Add an image, this will not start a new timeout, as one is pending. decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), + CreateDiscardablePaintImage(gfx::Size(1, 1)), base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -156,7 +130,7 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { bool locked = false; auto paint_image_1 = CreateDiscardablePaintImage(gfx::Size(1, 1)); decoded_image_tracker()->QueueImageDecode( - paint_image_1, gfx::ColorSpace(), + paint_image_1, base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -164,7 +138,7 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { auto paint_image_2 = CreateDiscardablePaintImage(gfx::Size(1, 1)); decoded_image_tracker()->QueueImageDecode( - paint_image_2, gfx::ColorSpace(), + paint_image_2, base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -172,11 +146,9 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { // Create dummy draw images for each: DrawImage draw_image_1(paint_image_1, SkIRect::MakeWH(1, 1), - kHigh_SkFilterQuality, SkMatrix::I(), 0, - gfx::ColorSpace()); + kHigh_SkFilterQuality, SkMatrix::I(), 0); DrawImage draw_image_2(paint_image_2, SkIRect::MakeWH(1, 1), - kHigh_SkFilterQuality, SkMatrix::I(), 0, - gfx::ColorSpace()); + kHigh_SkFilterQuality, SkMatrix::I(), 0); // Both should be in the cache: EXPECT_TRUE(image_controller()->IsDrawImageLocked(draw_image_1)); @@ -194,13 +166,13 @@ TEST_F(DecodedImageTrackerTest, UnlockAllImages) { // Insert two images: bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), + CreateDiscardablePaintImage(gfx::Size(1, 1)), base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); EXPECT_EQ(1u, image_controller()->num_locked_images()); decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), + CreateDiscardablePaintImage(gfx::Size(1, 1)), base::Bind([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); diff --git a/chromium/cc/tiles/frame_viewer_instrumentation.cc b/chromium/cc/tiles/frame_viewer_instrumentation.cc index 09ac5b6857d..c941820294e 100644 --- a/chromium/cc/tiles/frame_viewer_instrumentation.cc +++ b/chromium/cc/tiles/frame_viewer_instrumentation.cc @@ -9,13 +9,10 @@ namespace cc { namespace frame_viewer_instrumentation { -const char kCategoryLayerTree[] = - TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT( - "viz.quads") "," TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"); - namespace { -const char kCategory[] = "cc," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"); +constexpr const char kCategory[] = + "cc," TRACE_DISABLED_BY_DEFAULT("devtools.timeline"); const char kTileData[] = "tileData"; const char kLayerId[] = "layerId"; const char kTileId[] = "tileId"; @@ -69,7 +66,7 @@ ScopedRasterTask::~ScopedRasterTask() { bool IsTracingLayerTreeSnapshots() { bool category_enabled; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(kCategoryLayerTree, &category_enabled); + TRACE_EVENT_CATEGORY_GROUP_ENABLED(CategoryLayerTree(), &category_enabled); return category_enabled; } diff --git a/chromium/cc/tiles/frame_viewer_instrumentation.h b/chromium/cc/tiles/frame_viewer_instrumentation.h index d4cef013021..2f389bedbcb 100644 --- a/chromium/cc/tiles/frame_viewer_instrumentation.h +++ b/chromium/cc/tiles/frame_viewer_instrumentation.h @@ -12,7 +12,12 @@ namespace cc { namespace frame_viewer_instrumentation { -extern const char kCategoryLayerTree[]; +constexpr const char* CategoryLayerTree() { + // Declared as a constexpr function to have an external linkage and to be + // known at compile-time. + return TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT( + "viz.quads") "," TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"); +} class ScopedAnalyzeTask { public: diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc index 71550802821..6e3ae2ba974 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache.cc @@ -320,24 +320,20 @@ GpuImageDecodeCache::InUseCacheKey::FromDrawImage(const DrawImage& draw_image) { GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image) : frame_key(draw_image.frame_key()), upload_scale_mip_level(CalculateUploadScaleMipLevel(draw_image)), - filter_quality(CalculateDesiredFilterQuality(draw_image)), - target_color_space(draw_image.target_color_space()) {} + filter_quality(CalculateDesiredFilterQuality(draw_image)) {} bool GpuImageDecodeCache::InUseCacheKey::operator==( const InUseCacheKey& other) const { return frame_key == other.frame_key && upload_scale_mip_level == other.upload_scale_mip_level && - filter_quality == other.filter_quality && - target_color_space == other.target_color_space; + filter_quality == other.filter_quality; } size_t GpuImageDecodeCache::InUseCacheKeyHash::operator()( const InUseCacheKey& cache_key) const { - return base::HashInts( - cache_key.target_color_space.GetHash(), - base::HashInts(cache_key.frame_key.hash(), - base::HashInts(cache_key.upload_scale_mip_level, - cache_key.filter_quality))); + return base::HashInts(cache_key.frame_key.hash(), + base::HashInts(cache_key.upload_scale_mip_level, + cache_key.filter_quality)); } GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry( @@ -598,7 +594,6 @@ GpuImageDecodeCache::ImageData::ImageData( PaintImage::Id paint_image_id, DecodedDataMode mode, size_t size, - const gfx::ColorSpace& target_color_space, SkFilterQuality quality, int upload_scale_mip_level, bool needs_mips, @@ -606,7 +601,6 @@ GpuImageDecodeCache::ImageData::ImageData( : paint_image_id(paint_image_id), mode(mode), size(size), - target_color_space(target_color_space), quality(quality), upload_scale_mip_level(upload_scale_mip_level), needs_mips(needs_mips), @@ -668,7 +662,8 @@ GpuImageDecodeCache::GpuImageDecodeCache( SkColorType color_type, size_t max_working_set_bytes, int max_texture_size, - PaintImage::GeneratorClientId generator_client_id) + PaintImage::GeneratorClientId generator_client_id, + sk_sp<SkColorSpace> target_color_space) : color_type_(color_type), use_transfer_cache_(use_transfer_cache), context_(context), @@ -676,7 +671,8 @@ GpuImageDecodeCache::GpuImageDecodeCache( generator_client_id_(generator_client_id), persistent_cache_(PersistentCache::NO_AUTO_EVICT), max_working_set_bytes_(max_working_set_bytes), - max_working_set_items_(kMaxItemsInWorkingSet) { + max_working_set_items_(kMaxItemsInWorkingSet), + target_color_space_(std::move(target_color_space)) { // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). // Don't register a dump provider in these cases. if (base::ThreadTaskRunnerHandle::IsSet()) { @@ -734,6 +730,7 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( DecodeTaskType task_type) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::GetTaskForImageAndRef"); + if (SkipImage(draw_image)) return TaskResult(false); @@ -1114,10 +1111,13 @@ void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) { gr_context_access.emplace(context_); base::AutoLock lock(lock_); - ImageData* image_data = GetImageDataForDrawImage( - draw_image, InUseCacheKey::FromDrawImage(draw_image)); + auto cache_key = InUseCacheKey::FromDrawImage(draw_image); + ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); DCHECK(image_data); DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding"; + + if (image_data->is_bitmap_backed) + DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster); UploadImageIfNecessary(draw_image, image_data); } @@ -1183,7 +1183,8 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef( ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); DCHECK(image_data); - if (image_data->decode.is_locked()) { + // No decode is necessary for bitmap backed images. + if (image_data->decode.is_locked() || image_data->is_bitmap_backed) { // We should never be creating a decode task for a not budgeted image. DCHECK(image_data->is_budgeted); // We should never be creating a decode for an already-uploaded image. @@ -1526,15 +1527,12 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, DCHECK_GT(image_data->decode.ref_count, 0u); DCHECK_GT(image_data->upload.ref_count, 0u); - sk_sp<SkColorSpace> target_color_space = - SupportsColorSpaceConversion() && - draw_image.target_color_space().IsValid() - ? draw_image.target_color_space().ToSkColorSpace() - : nullptr; - if (target_color_space && - SkColorSpace::Equals(target_color_space.get(), + sk_sp<SkColorSpace> color_space = + SupportsColorSpaceConversion() ? target_color_space_ : nullptr; + if (color_space && + SkColorSpace::Equals(color_space.get(), image_data->decode.image()->colorSpace())) { - target_color_space = nullptr; + color_space = nullptr; } if (image_data->mode == DecodedDataMode::kTransferCache) { @@ -1543,7 +1541,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, if (!image_data->decode.image()->peekPixels(&pixmap)) return; - ClientImageTransferCacheEntry image_entry(&pixmap, target_color_space.get(), + ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(), image_data->needs_mips); size_t size = image_entry.SerializedSize(); void* data = context_->ContextSupport()->MapTransferCacheEntry(size); @@ -1578,7 +1576,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, DCHECK(!use_transfer_cache_); base::AutoUnlock unlock(lock_); uploaded_image = MakeTextureImage( - context_, std::move(uploaded_image), target_color_space, + context_, std::move(uploaded_image), color_space, image_data->needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo); } @@ -1657,7 +1655,6 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { !cache_color_conversion_on_cpu; return base::WrapRefCounted( new ImageData(draw_image.paint_image().stable_id(), mode, data_size, - draw_image.target_color_space(), CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, needs_mips, is_bitmap_backed)); } @@ -1884,10 +1881,6 @@ bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data, image_data->upload_scale_mip_level; bool quality_is_compatible = CalculateDesiredFilterQuality(draw_image) <= image_data->quality; - bool color_is_compatible = - image_data->target_color_space == draw_image.target_color_space(); - if (!color_is_compatible) - return false; if (is_scaled && (!scale_is_compatible || !quality_is_compatible)) return false; return true; @@ -1970,7 +1963,7 @@ sk_sp<SkColorSpace> GpuImageDecodeCache::ColorSpaceForImageDecode( return nullptr; if (mode == DecodedDataMode::kCpu) - return image.target_color_space().ToSkColorSpace(); + return target_color_space_; // For kGpu or kTransferCache images color conversion is handled during // upload, so keep the original colorspace here. diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h index dd21622a83d..a167341ecbe 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.h +++ b/chromium/cc/tiles/gpu_image_decode_cache.h @@ -106,7 +106,8 @@ class CC_EXPORT GpuImageDecodeCache SkColorType color_type, size_t max_working_set_bytes, int max_texture_size, - PaintImage::GeneratorClientId client_id); + PaintImage::GeneratorClientId client_id, + sk_sp<SkColorSpace> target_color_space); ~GpuImageDecodeCache() override; // Returns the GL texture ID backing the given SkImage. @@ -307,7 +308,6 @@ class CC_EXPORT GpuImageDecodeCache ImageData(PaintImage::Id paint_image_id, DecodedDataMode mode, size_t size, - const gfx::ColorSpace& target_color_space, SkFilterQuality quality, int upload_scale_mip_level, bool needs_mips, @@ -320,7 +320,6 @@ class CC_EXPORT GpuImageDecodeCache const PaintImage::Id paint_image_id; const DecodedDataMode mode; const size_t size; - gfx::ColorSpace target_color_space; SkFilterQuality quality; int upload_scale_mip_level; bool needs_mips = false; @@ -365,7 +364,6 @@ class CC_EXPORT GpuImageDecodeCache PaintImage::FrameKey frame_key; int upload_scale_mip_level; SkFilterQuality filter_quality; - gfx::ColorSpace target_color_space; }; struct InUseCacheKeyHash { size_t operator()(const InUseCacheKey&) const; @@ -512,6 +510,7 @@ class CC_EXPORT GpuImageDecodeCache std::vector<SkImage*> images_pending_complete_lock_; std::vector<SkImage*> images_pending_unlock_; std::vector<sk_sp<SkImage>> images_pending_deletion_; + const sk_sp<SkColorSpace> target_color_space_; std::vector<uint32_t> ids_pending_unlock_; std::vector<uint32_t> ids_pending_deletion_; diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc index 85a7f169741..11e0e09eeae 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc @@ -47,19 +47,20 @@ class GpuImageDecodeCachePerfTest kTimeCheckInterval), context_provider_(base::MakeRefCounted<TestInProcessContextProvider>( UseTransferCache(), - false /* support_locking */)), - cache_(context_provider_.get(), - UseTransferCache(), - kRGBA_8888_SkColorType, - kCacheSize, - MaxTextureSize(), - PaintImage::kDefaultGeneratorClientId) { + false /* support_locking */)) { // Initializing context here is ok because image decode cache does not use // context provider in its constructor. gpu::ContextResult result = context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); } + void CreateCache(sk_sp<SkColorSpace> color_space = nullptr) { + cache_ = std::make_unique<GpuImageDecodeCache>( + context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType, + kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId, + std::move(color_space)); + } + protected: size_t MaxTextureSize() const { switch (GetParam()) { @@ -88,7 +89,7 @@ class GpuImageDecodeCachePerfTest LapTimer timer_; scoped_refptr<TestInProcessContextProvider> context_provider_; - GpuImageDecodeCache cache_; + std::unique_ptr<GpuImageDecodeCache> cache_; }; INSTANTIATE_TEST_CASE_P(P, @@ -98,6 +99,7 @@ INSTANTIATE_TEST_CASE_P(P, TestMode::kSw)); TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) { + CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace()); timer_.Reset(); do { DrawImage image( @@ -106,11 +108,10 @@ TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) { .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u, - gfx::ColorSpace::CreateXYZD50()); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u); - DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); - cache_.DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); + cache_->DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -131,6 +132,7 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { context_provider_->GrContext(), SkBudgeted::kNo, SkImageInfo::MakeN32Premul(2048, 2048)); + CreateCache(); timer_.Reset(); do { DrawImage image( @@ -139,9 +141,9 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace()); + CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u); - DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); + DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); if (GetParam() == TestMode::kGpu) { SkPaint paint; @@ -152,7 +154,7 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { surface->prepareForExternalIO(); } - cache_.DrawWithImageFinished(image, decoded_image); + cache_->DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -162,21 +164,21 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { TEST_P(GpuImageDecodeCachePerfTest, AcquireExistingImages) { timer_.Reset(); + CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace()); DrawImage image( PaintImageBuilder::WithDefault() .set_id(PaintImage::GetNextId()) .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u, - gfx::ColorSpace::CreateXYZD50()); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u); - DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); - cache_.DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); + cache_->DrawWithImageFinished(image, decoded_image); do { - DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); - cache_.DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); + cache_->DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc index fc570ccbde2..526c1dd4aaf 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc @@ -273,10 +273,15 @@ class GpuImageDecodeCacheTest } std::unique_ptr<GpuImageDecodeCache> CreateCache() { + return CreateCache(DefaultColorSpace()); + } + + std::unique_ptr<GpuImageDecodeCache> CreateCache( + const gfx::ColorSpace& color_space) { return std::make_unique<GpuImageDecodeCache>( context_provider_.get(), use_transfer_cache_, color_type_, kGpuMemoryLimitBytes, max_texture_size_, - PaintImage::kDefaultGeneratorClientId); + PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace()); } PaintImage CreatePaintImageInternal( @@ -363,7 +368,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -372,7 +377,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -394,7 +399,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -403,7 +408,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -424,7 +429,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kHigh_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -432,8 +437,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -455,7 +459,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -466,7 +470,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { second_image, SkIRect::MakeWH(second_image.width(), second_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -491,7 +495,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -505,7 +509,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -515,7 +519,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage third_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -537,7 +541,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -546,7 +550,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -556,7 +560,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage third_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -580,8 +584,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100)); DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -594,8 +597,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -616,7 +618,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -658,7 +660,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -700,7 +702,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -731,7 +733,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -774,7 +776,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -821,7 +823,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -850,7 +852,7 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -880,7 +882,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -912,7 +914,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -948,7 +950,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -982,7 +984,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -994,7 +996,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { DrawImage larger_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef( larger_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(larger_result.need_unref); @@ -1036,7 +1038,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1047,8 +1049,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { DrawImage higher_quality_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef( higher_quality_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(hq_result.need_unref); @@ -1090,7 +1091,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1124,7 +1125,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1166,7 +1167,7 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1207,7 +1208,7 @@ TEST_P(GpuImageDecodeCacheTest, DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1244,7 +1245,7 @@ TEST_P(GpuImageDecodeCacheTest, DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1281,7 +1282,7 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1307,7 +1308,7 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { DrawImage draw_image( image, SkIRect::MakeXYWH(150, 150, image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1333,7 +1334,7 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) { DrawImage draw_image( image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1359,7 +1360,7 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); { ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); @@ -1421,7 +1422,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1436,7 +1437,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1469,7 +1470,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1488,7 +1489,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1512,10 +1513,9 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); // Create an image with kLow_FilterQuality. - DrawImage low_draw_image(image, - SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage low_draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), + kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef( low_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(low_result.need_unref); @@ -1525,8 +1525,7 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // should get a new task/ref. DrawImage medium_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef( medium_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(medium_result.need_unref); @@ -1536,8 +1535,7 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // Get the same image at kHigh_FilterQuality. We should re-use medium. DrawImage large_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult large_result = cache->GetTaskForImageAndRef( large_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(large_result.need_unref); @@ -1565,7 +1563,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1587,7 +1585,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { DrawImage draw_image_mips( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips)); cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image); @@ -1601,7 +1599,7 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) { SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); @@ -1629,7 +1627,7 @@ TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1680,13 +1678,13 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); PaintImage image2 = CreatePaintImageInternal(gfx::Size(100, 100)); DrawImage draw_image2( image2, SkIRect::MakeWH(image2.width(), image2.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // Add an image to the cache and un-ref it. { @@ -1763,7 +1761,7 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1793,7 +1791,7 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1818,65 +1816,17 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u); } -TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) { - auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - - gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB(); - gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50(); - - PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100)); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); - ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( - first_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(first_result.need_unref); - EXPECT_TRUE(first_result.task); - - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_b); - ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( - second_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(second_result.need_unref); - EXPECT_TRUE(second_result.task); - EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); - ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( - third_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(third_result.need_unref); - EXPECT_TRUE(third_result.task.get() == first_result.task.get()); - - TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get()); - TestTileTaskRunner::ProcessTask(first_result.task.get()); - TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get()); - TestTileTaskRunner::ProcessTask(second_result.task.get()); - - cache->UnrefImage(first_draw_image); - cache->UnrefImage(second_draw_image); - cache->UnrefImage(third_draw_image); -} - -TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) { +TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImage) { auto cache = CreateCache(); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); // Create an image that's too large to cache. PaintImage image = CreatePaintImageInternal(gfx::Size(1, 24000)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1909,10 +1859,9 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - 1u, DefaultColorSpace()); + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u); auto decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -1922,8 +1871,7 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { cache->DrawWithImageFinished(draw_image, decoded_image); // Scaled. - DrawImage scaled_draw_image(draw_image, 0.5f, 2u, - draw_image.target_color_space()); + DrawImage scaled_draw_image(draw_image, 0.5f, 2u); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(scaled_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -1935,8 +1883,7 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { // Subset. DrawImage subset_draw_image( image, SkIRect::MakeWH(5, 5), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, - DefaultColorSpace()); + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -1956,7 +1903,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1970,7 +1917,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -2014,7 +1961,7 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2051,7 +1998,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // The image counts against our budget. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -2065,7 +2012,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { CreatePaintImageInternal(gfx::Size(100, 100)), SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); @@ -2095,7 +2042,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // The image counts against our budget. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -2109,7 +2056,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { CreateDiscardablePaintImage(gfx::Size(100, 100)), SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); @@ -2127,17 +2074,17 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) { - auto cache = CreateCache(); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); + auto cache = CreateCache(color_space); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); // Create an image that's too large to upload. PaintImage image = CreatePaintImageInternal(gfx::Size(1, 24000)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2182,16 +2129,16 @@ TEST_P(GpuImageDecodeCacheTest, TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) { - auto cache = CreateCache(); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); + auto cache = CreateCache(color_space); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2239,7 +2186,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2251,7 +2198,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) { EXPECT_FALSE(cache->GetSWImageDecodeForTesting(draw_image)); } -TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScaleTask) { +TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) { auto cache = CreateCache(); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; @@ -2260,19 +2207,41 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScaleTask) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); EXPECT_TRUE(result.task); - TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + EXPECT_TRUE(result.task->dependencies().empty()); TestTileTaskRunner::ProcessTask(result.task.get()); cache->UnrefImage(draw_image); } -TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { +TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) { auto cache = CreateCache(); + bool is_decomposable = true; + SkFilterQuality quality = kHigh_SkFilterQuality; + + PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10)); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex); + auto result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + EXPECT_TRUE(result.task); + EXPECT_TRUE(result.task->dependencies().empty()); + TestTileTaskRunner::CancelTask(result.task.get()); + TestTileTaskRunner::CompleteTask(result.task.get()); + + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { + auto color_space = gfx::ColorSpace::CreateDisplayP3D65(); + auto cache = CreateCache(color_space); const bool should_cache_sw_image = cache->SupportsColorSpaceConversion() && !use_transfer_cache_; @@ -2280,10 +2249,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 24000)); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65()); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2295,9 +2264,8 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { auto sw_image = cache->GetSWImageDecodeForTesting(draw_image); ASSERT_EQ(!!sw_image, should_cache_sw_image); if (should_cache_sw_image) { - EXPECT_TRUE(SkColorSpace::Equals( - sw_image->colorSpace(), - gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get())); + EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(), + color_space.ToSkColorSpace().get())); } } @@ -2310,7 +2278,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2341,7 +2309,7 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2393,7 +2361,7 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image1( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image1 = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image1)); ASSERT_TRUE(decoded_image1.image()); @@ -2430,7 +2398,7 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2446,15 +2414,16 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { TEST_P(GpuImageDecodeCacheTest, BasicMips) { auto decode_and_check_mips = [this](SkFilterQuality filter_quality, - SkSize scale, gfx::ColorSpace color_space, + SkSize scale, + const gfx::ColorSpace& color_space, bool should_have_mips) { - auto cache = CreateCache(); + auto cache = CreateCache(color_space); bool is_decomposable = true; PaintImage image = CreatePaintImageInternal(gfx::Size(100, 100)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(scale, is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2515,7 +2484,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2552,7 +2521,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2601,7 +2570,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2632,7 +2601,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc index dfa0bfc2750..473c7c25d5f 100644 --- a/chromium/cc/tiles/image_controller_unittest.cc +++ b/chromium/cc/tiles/image_controller_unittest.cc @@ -229,7 +229,7 @@ DrawImage CreateDiscardableDrawImage(gfx::Size size) { return DrawImage(CreateDiscardablePaintImage(size), SkIRect::MakeWH(size.width(), size.height()), kNone_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex, gfx::ColorSpace()); + PaintImage::kDefaultFrameIndex); } DrawImage CreateBitmapDrawImage(gfx::Size size) { diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc index 13b5f9396f8..c16c0bb291b 100644 --- a/chromium/cc/tiles/picture_layer_tiling.cc +++ b/chromium/cc/tiles/picture_layer_tiling.cc @@ -15,7 +15,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/math_util.h" #include "cc/raster/raster_source.h" #include "cc/tiles/prioritized_tile.h" diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc index d75e6e2001f..0dbd879ccf9 100644 --- a/chromium/cc/tiles/software_image_decode_cache.cc +++ b/chromium/cc/tiles/software_image_decode_cache.cc @@ -16,6 +16,7 @@ #include "cc/base/histograms.h" #include "cc/raster/tile_task.h" #include "cc/tiles/mipmap_util.h" +#include "ui/gfx/color_space.h" #include "ui/gfx/skia_util.h" using base::trace_event::MemoryAllocatorDump; @@ -140,8 +141,10 @@ void RecordLockExistingCachedImageHistogram(TilePriority::PriorityBin bin, SoftwareImageDecodeCache::SoftwareImageDecodeCache( SkColorType color_type, size_t locked_memory_limit_bytes, - PaintImage::GeneratorClientId generator_client_id) + PaintImage::GeneratorClientId generator_client_id, + sk_sp<SkColorSpace> target_color_space) : decoded_images_(ImageMRUCache::NO_AUTO_EVICT), + target_color_space_(std::move(target_color_space)), locked_images_budget_(locked_memory_limit_bytes), color_type_(color_type), generator_client_id_(generator_client_id), @@ -362,8 +365,9 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( // If we can use the original decode, we'll definitely need a decode. if (key.type() == CacheKey::kOriginal) { base::AutoUnlock release(lock_); - local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_, - generator_client_id_); + local_cache_entry = + Utils::DoDecodeImage(key, paint_image, color_type_, target_color_space_, + generator_client_id_); } else { // Attempt to find a cached decode to generate a scaled/subrected decode // from. @@ -390,8 +394,9 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( DCHECK(!should_decode_to_scale || !key.is_nearest_neighbor()); if (should_decode_to_scale) { base::AutoUnlock release(lock_); - local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_, - generator_client_id_); + local_cache_entry = + Utils::DoDecodeImage(key, paint_image, color_type_, + target_color_space_, generator_client_id_); } // Couldn't decode to scale or find a cached candidate. Create the @@ -416,9 +421,9 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( key.type() == CacheKey::kSubrectOriginal ? SkIRect::MakeWH(paint_image.width(), paint_image.height()) : gfx::RectToSkIRect(key.src_rect()); - DrawImage candidate_draw_image( - paint_image, src_rect, kNone_SkFilterQuality, SkMatrix::I(), - key.frame_key().frame_index(), key.target_color_space()); + DrawImage candidate_draw_image(paint_image, src_rect, + kNone_SkFilterQuality, SkMatrix::I(), + key.frame_key().frame_index()); candidate_key.emplace( CacheKey::FromDrawImage(candidate_draw_image, color_type_)); } @@ -519,9 +524,7 @@ bool SoftwareImageDecodeCache::UseCacheForDrawImage( // Cache images that need to be converted to a non-sRGB color space. // TODO(ccameron): Consider caching when any color conversion is required. // https://crbug.com/791828 - const gfx::ColorSpace& dst_color_space = draw_image.target_color_space(); - if (dst_color_space.IsValid() && - dst_color_space != gfx::ColorSpace::CreateSRGB()) { + if (target_color_space_ && !target_color_space_->isSRGB()) { return true; } diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h index 30040d1da66..eb7cc161f1d 100644 --- a/chromium/cc/tiles/software_image_decode_cache.h +++ b/chromium/cc/tiles/software_image_decode_cache.h @@ -34,7 +34,8 @@ class CC_EXPORT SoftwareImageDecodeCache SoftwareImageDecodeCache(SkColorType color_type, size_t locked_memory_limit_bytes, - PaintImage::GeneratorClientId generator_client_id); + PaintImage::GeneratorClientId generator_client_id, + sk_sp<SkColorSpace> target_color_space); ~SoftwareImageDecodeCache() override; // ImageDecodeCache overrides. @@ -150,6 +151,7 @@ class CC_EXPORT SoftwareImageDecodeCache PaintImage::FrameKeyHash> frame_key_to_image_keys_; + const sk_sp<SkColorSpace> target_color_space_; MemoryBudget locked_images_budget_; const SkColorType color_type_; diff --git a/chromium/cc/tiles/software_image_decode_cache_perftest.cc b/chromium/cc/tiles/software_image_decode_cache_perftest.cc index 64d79679c8b..5f693179b1c 100644 --- a/chromium/cc/tiles/software_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/software_image_decode_cache_perftest.cc @@ -63,8 +63,7 @@ class SoftwareImageDecodeCachePerfTest : public testing::Test { PaintImage::GetNextContentId()) .TakePaintImage(), subrect, quality, - CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u, - gfx::ColorSpace()); + CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u); } } } diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc index abae6c64e6c..18f6d88444b 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc @@ -23,9 +23,13 @@ size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024; class TestSoftwareImageDecodeCache : public SoftwareImageDecodeCache { public: TestSoftwareImageDecodeCache() + : TestSoftwareImageDecodeCache(DefaultColorSpace()) {} + + explicit TestSoftwareImageDecodeCache(const gfx::ColorSpace& color_space) : SoftwareImageDecodeCache(kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId) {} + PaintImage::kDefaultGeneratorClientId, + color_space.ToSkColorSpace()) {} }; SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { @@ -54,7 +58,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kNone_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -76,7 +80,7 @@ TEST(SoftwareImageDecodeCacheTest, paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -94,7 +98,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropsToLowIfMipLevel0) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -113,7 +117,7 @@ TEST(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kARGB_4444_SkColorType); @@ -132,7 +136,7 @@ TEST(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kHigh_SkFilterQuality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kARGB_4444_SkColorType); @@ -151,7 +155,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -171,7 +175,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.4f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -190,7 +194,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -210,7 +214,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -231,7 +235,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -252,7 +256,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -273,7 +277,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -294,7 +298,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -314,7 +318,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -334,7 +338,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -354,7 +358,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -373,7 +377,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -392,7 +396,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -411,7 +415,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -431,7 +435,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -450,7 +454,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -473,7 +477,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.45f, 0.45f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -493,7 +497,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -513,7 +517,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -534,7 +538,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -555,7 +559,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -567,6 +571,41 @@ TEST(SoftwareImageDecodeCacheTest, EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } +TEST(SoftwareImageDecodeCacheTest, ImageKeyDownscaleMipLevelWithRounding) { + // Tests that, when using a non-zero mip level, the final target size (which + // is the size of the chosen mip level) is as expected if rounding is + // required. + // + // The 97x61 dimensions and the (0.2f, 0.2f) scaling were chosen specifically + // so that: + // + // - The starting target size is 19x12 which means that 2 is the chosen mip + // level. + // + // - Attempting to get the final target size by simply multiplying the + // dimensions of the |src_rect| (97x61) times + // MipMapUtil::GetScaleAdjustmentForLevel() yields 24x15 if we attempt to + // store the result as integers. This is inconsistent with the rounding + // behavior introduced in https://crrev.com/c/1107049 and was the cause of + // https://crbug.com/891316. + PaintImage paint_image = CreatePaintImage(97, 61); + bool is_decomposable = true; + DrawImage draw_image( + paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), + kMedium_SkFilterQuality, + CreateMatrix(SkSize::Make(0.2f, 0.2f), is_decomposable), + PaintImage::kDefaultFrameIndex); + + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); + EXPECT_EQ(draw_image.frame_key(), key.frame_key()); + EXPECT_FALSE(key.is_nearest_neighbor()); + EXPECT_EQ(25, key.target_size().width()); + EXPECT_EQ(16, key.target_size().height()); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); + EXPECT_EQ(25u * 16u * 4u, key.locked_bytes()); +} + TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) { PaintImage paint_image = CreatePaintImage(100, 100); bool is_decomposable = true; @@ -575,7 +614,7 @@ TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -589,7 +628,7 @@ TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) { DrawImage another_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto another_key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( another_draw_image, kN32_SkColorType); @@ -612,7 +651,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) { paint_image, SkIRect::MakeXYWH(25, 35, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -633,7 +672,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) { paint_image, SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -654,7 +693,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -663,7 +702,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage another_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult another_result = cache.GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -684,7 +723,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -714,7 +753,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kHigh_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult high_quality_result = cache.GetTaskForImageAndRef(high_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -725,7 +764,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kNone_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult none_quality_result = cache.GetTaskForImageAndRef(none_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -749,7 +788,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) { DrawImage half_size_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult half_size_result = cache.GetTaskForImageAndRef( half_size_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(half_size_result.need_unref); @@ -758,7 +797,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) { DrawImage quarter_size_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult quarter_size_result = cache.GetTaskForImageAndRef(quarter_size_draw_image, ImageDecodeCache::TracingInfo()); @@ -783,7 +822,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) { first_paint_image, SkIRect::MakeWH(first_paint_image.width(), first_paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -794,75 +833,18 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) { second_paint_image, SkIRect::MakeWH(second_paint_image.width(), second_paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef( - second_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(second_result.need_unref); - EXPECT_TRUE(second_result.task); - EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - - TestTileTaskRunner::ProcessTask(first_result.task.get()); - TestTileTaskRunner::ProcessTask(second_result.task.get()); - - cache.UnrefImage(first_draw_image); - cache.UnrefImage(second_draw_image); -} - -// crbug.com/709341 -#if defined(MEMORY_SANITIZER) -#define MAYBE_GetTaskForImageDifferentColorSpace \ - DISABLED_GetTaskForImageDifferentColorSpace -#else -#define MAYBE_GetTaskForImageDifferentColorSpace \ - GetTaskForImageDifferentColorSpace -#endif -TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) { - TestSoftwareImageDecodeCache cache; - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - - gfx::ColorSpace color_space_a(gfx::ColorSpace::PrimaryID::XYZ_D50, - gfx::ColorSpace::TransferID::IEC61966_2_1); - gfx::ColorSpace color_space_b(gfx::ColorSpace::PrimaryID::SMPTE170M, - gfx::ColorSpace::TransferID::IEC61966_2_1); - gfx::ColorSpace color_space_c = gfx::ColorSpace::CreateSRGB(); - - PaintImage paint_image = CreatePaintImage(100, 100, color_space_a); - DrawImage first_draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_b); - ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef( - first_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(first_result.need_unref); - EXPECT_TRUE(first_result.task); - - DrawImage second_draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_c); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_b); - ImageDecodeCache::TaskResult third_result = cache.GetTaskForImageAndRef( - third_draw_image, ImageDecodeCache::TracingInfo()); - EXPECT_TRUE(third_result.need_unref); - EXPECT_TRUE(third_result.task); - EXPECT_TRUE(first_result.task.get() == third_result.task.get()); - TestTileTaskRunner::ProcessTask(first_result.task.get()); TestTileTaskRunner::ProcessTask(second_result.task.get()); cache.UnrefImage(first_draw_image); cache.UnrefImage(second_draw_image); - cache.UnrefImage(third_draw_image); } TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) { @@ -874,7 +856,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -903,7 +885,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -938,7 +920,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -979,7 +961,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1019,7 +1001,7 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1052,7 +1034,7 @@ TEST(SoftwareImageDecodeCacheTest, paint_image, SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1083,7 +1065,7 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1108,7 +1090,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1138,7 +1120,7 @@ TEST(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1162,7 +1144,7 @@ TEST(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { paint_image, SkIRect::MakeXYWH(150, 150, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1185,7 +1167,7 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1213,7 +1195,7 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) { PaintImage paint_image = CreatePaintImage(100, 100); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1246,7 +1228,7 @@ TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) { PaintImage paint_image = CreatePaintImage(100, 100); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1277,7 +1259,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1308,7 +1290,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1339,7 +1321,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1370,7 +1352,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1401,7 +1383,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1432,7 +1414,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1463,7 +1445,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1494,7 +1476,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1518,11 +1500,11 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image_50( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DrawImage draw_image_49( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result_50 = cache.GetTaskForImageAndRef( draw_image_50, ImageDecodeCache::TracingInfo()); @@ -1569,7 +1551,7 @@ TEST(SoftwareImageDecodeCacheTest, ClearCache) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1604,10 +1586,9 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - 1u, DefaultColorSpace()); + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u); auto decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1616,8 +1597,7 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { cache.DrawWithImageFinished(draw_image, decoded_image); // Scaled. - DrawImage scaled_draw_image(draw_image, 0.5f, 2u, - draw_image.target_color_space()); + DrawImage scaled_draw_image(draw_image, 0.5f, 2u); decoded_image = cache.GetDecodedImageForDraw(scaled_draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1628,8 +1608,7 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { // Subset. DrawImage subset_draw_image( image, SkIRect::MakeWH(5, 5), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, - DefaultColorSpace()); + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u); decoded_image = cache.GetDecodedImageForDraw(subset_draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1649,7 +1628,7 @@ TEST(SoftwareImageDecodeCacheTest, SizeSubrectingIsHandled) { DefaultColorSpace().ToSkColorSpace(), false); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(0, 0, 10, 10), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1682,7 +1661,7 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { gfx::Size(100, 100), DefaultColorSpace().ToSkColorSpace()); DrawImage draw_image(paint_image, SkIRect::MakeWH(100, 100), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); EXPECT_TRUE(decoded_draw_image.image()); @@ -1692,7 +1671,7 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { DrawImage empty_draw_image( paint_image, SkIRect::MakeEmpty(), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage empty_decoded_draw_image = cache.GetDecodedImageForDraw(empty_draw_image); EXPECT_FALSE(empty_decoded_draw_image.image()); @@ -1700,16 +1679,16 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { } TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) { - TestSoftwareImageDecodeCache cache; + gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65(); + TestSoftwareImageDecodeCache cache(target_color_space); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage paint_image = CreateBitmapImage(gfx::Size(100, 100)); DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, target_color_space); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1733,7 +1712,7 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); // The cache should not support this image. EXPECT_FALSE(cache.UseCacheForDrawImage(draw_image)); @@ -1759,7 +1738,7 @@ TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(scale, scale), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); EXPECT_TRUE(decoded_draw_image.image()); @@ -1798,7 +1777,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image1( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image1 = cache.GetDecodedImageForDraw(draw_image1); ASSERT_TRUE(decoded_image1.image()); EXPECT_EQ(decoded_image1.image()->width(), 50); @@ -1815,7 +1794,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image2( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25, 0.25), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image2 = cache.GetDecodedImageForDraw(draw_image2); ASSERT_TRUE(decoded_image2.image()); EXPECT_EQ(decoded_image2.image()->width(), 25); @@ -1855,7 +1834,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) { // subrect vetoes decode to scale. DrawImage draw_image(paint_image, SkIRect::MakeWH(50, 50), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); EXPECT_EQ(decoded_image.image()->width(), 25); @@ -1891,7 +1870,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage::kDefaultFrameIndex); DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); EXPECT_EQ(decoded_image.image()->width(), 100); diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc index 5052a2a5d21..03d3e09e2f5 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc @@ -50,7 +50,7 @@ class BaseTest : public testing::Test { ? SkIRect::MakeWH(paint_image().width(), paint_image().height()) : src_rect, kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(scale, scale), true), - PaintImage::kDefaultFrameIndex, GetColorSpace()); + PaintImage::kDefaultFrameIndex); } SoftwareImageDecodeCache& cache() { return *cache_; } @@ -80,7 +80,8 @@ class N32Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::kDefaultGeneratorClientId, + GetColorSpace().ToSkColorSpace()); } }; @@ -89,7 +90,8 @@ class RGBA4444Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kARGB_4444_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::kDefaultGeneratorClientId, + GetColorSpace().ToSkColorSpace()); } }; @@ -98,7 +100,8 @@ class RGBA_F16Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kRGBA_F16_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId); + PaintImage::kDefaultGeneratorClientId, + GetColorSpace().ToSkColorSpace()); } }; @@ -135,9 +138,6 @@ class Predecode : public virtual BaseTest { const DrawImage& draw_image, const gfx::Size& expected_size) override { auto decoded = cache().GetDecodedImageForDraw(draw_image); - EXPECT_TRUE(SkColorSpace::Equals( - decoded.image()->colorSpace(), - draw_image.target_color_space().ToSkColorSpace().get())); SCOPED_TRACE(base::StringPrintf("Failure from line %d", line)); EXPECT_EQ(decoded.image()->width(), expected_size.width()); EXPECT_EQ(decoded.image()->height(), expected_size.height()); diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.cc b/chromium/cc/tiles/software_image_decode_cache_utils.cc index 58bf110a3a6..16f5d11b30e 100644 --- a/chromium/cc/tiles/software_image_decode_cache_utils.cc +++ b/chromium/cc/tiles/software_image_decode_cache_utils.cc @@ -59,6 +59,7 @@ SoftwareImageDecodeCacheUtils::DoDecodeImage( const CacheKey& key, const PaintImage& paint_image, SkColorType color_type, + sk_sp<SkColorSpace> color_space, PaintImage::GeneratorClientId client_id) { SkISize target_size = SkISize::Make(key.target_size().width(), key.target_size().height()); @@ -74,7 +75,7 @@ SoftwareImageDecodeCacheUtils::DoDecodeImage( "SoftwareImageDecodeCacheUtils::DoDecodeImage - " "decode"); bool result = paint_image.Decode(target_pixels->data(), &target_info, - key.target_color_space().ToSkColorSpace(), + std::move(color_space), key.frame_key().frame_index(), client_id); if (!result) { target_pixels->Unlock(); @@ -180,7 +181,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, // the filter quality doesn't matter. Early out instead. if (target_size.IsEmpty()) { return CacheKey(frame_key, stable_id, kSubrectAndScale, false, src_rect, - target_size, image.target_color_space()); + target_size); } ProcessingType type = kOriginal; @@ -202,14 +203,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, } else { type = kSubrectAndScale; // Update the target size to be a mip level size. - // TODO(vmpstr): MipMapUtil and JPEG decoders disagree on what to do with - // odd sizes. If width = 2k + 1, and the mip level is 1, then this will - // return width = k; JPEG decoder, however, will support decoding to width = - // k + 1. We need to figure out what to do in this case. - SkSize mip_scale_adjustment = - MipMapUtil::GetScaleAdjustmentForLevel(src_rect.size(), mip_level); - target_size.set_width(src_rect.width() * mip_scale_adjustment.width()); - target_size.set_height(src_rect.height() * mip_scale_adjustment.height()); + target_size = MipMapUtil::GetSizeForLevel(src_rect.size(), mip_level); } // If the original image is large, we might want to do a subrect instead if @@ -240,7 +234,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, } return CacheKey(frame_key, stable_id, type, is_nearest_neighbor, src_rect, - target_size, image.target_color_space()); + target_size); } SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( @@ -249,15 +243,13 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( ProcessingType type, bool is_nearest_neighbor, const gfx::Rect& src_rect, - const gfx::Size& target_size, - const gfx::ColorSpace& target_color_space) + const gfx::Size& target_size) : frame_key_(frame_key), stable_id_(stable_id), type_(type), is_nearest_neighbor_(is_nearest_neighbor), src_rect_(src_rect), - target_size_(target_size), - target_color_space_(target_color_space) { + target_size_(target_size) { if (type == kOriginal) { hash_ = frame_key_.hash(); } else { @@ -274,8 +266,6 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash), frame_key_.hash()); } - // Include the target color space in the hash regardless of scaling. - hash_ = base::HashInts(hash_, target_color_space.GetHash()); } SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(const CacheKey& other) = @@ -297,7 +287,6 @@ std::string SoftwareImageDecodeCacheUtils::CacheKey::ToString() const { } str << "]\nis_nearest_neightbor[" << is_nearest_neighbor_ << "]\nsrc_rect[" << src_rect_.ToString() << "]\ntarget_size[" << target_size_.ToString() - << "]\ntarget_color_space[" << target_color_space_.ToString() << "]\nhash[" << hash_ << "]"; return str.str(); } diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.h b/chromium/cc/tiles/software_image_decode_cache_utils.h index 835d68c8492..42d7b0205ce 100644 --- a/chromium/cc/tiles/software_image_decode_cache_utils.h +++ b/chromium/cc/tiles/software_image_decode_cache_utils.h @@ -16,7 +16,6 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkSize.h" -#include "ui/gfx/color_space.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -57,7 +56,6 @@ class SoftwareImageDecodeCacheUtils { // image. DCHECK(!is_nearest_neighbor_ || type_ == kOriginal); return frame_key_ == other.frame_key_ && type_ == other.type_ && - target_color_space_ == other.target_color_space_ && (type_ == kOriginal || (src_rect_ == other.src_rect_ && target_size_ == other.target_size_)); } @@ -70,9 +68,6 @@ class SoftwareImageDecodeCacheUtils { bool is_nearest_neighbor() const { return is_nearest_neighbor_; } gfx::Rect src_rect() const { return src_rect_; } gfx::Size target_size() const { return target_size_; } - const gfx::ColorSpace& target_color_space() const { - return target_color_space_; - } size_t get_hash() const { return hash_; } @@ -94,8 +89,7 @@ class SoftwareImageDecodeCacheUtils { ProcessingType type, bool is_nearest_neighbor, const gfx::Rect& src_rect, - const gfx::Size& size, - const gfx::ColorSpace& target_color_space); + const gfx::Size& size); PaintImage::FrameKey frame_key_; // The stable id is does not factor into the cache key's value for hashing @@ -106,7 +100,6 @@ class SoftwareImageDecodeCacheUtils { bool is_nearest_neighbor_; gfx::Rect src_rect_; gfx::Size target_size_; - gfx::ColorSpace target_color_space_; size_t hash_; }; @@ -186,6 +179,7 @@ class SoftwareImageDecodeCacheUtils { const CacheKey& key, const PaintImage& image, SkColorType color_type, + sk_sp<SkColorSpace> color_space, PaintImage::GeneratorClientId client_id); static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate( const CacheKey& key, diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc index db0ba9f0177..96962c83b25 100644 --- a/chromium/cc/tiles/tile.cc +++ b/chromium/cc/tiles/tile.cc @@ -10,7 +10,7 @@ #include "base/numerics/safe_conversions.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/math_util.h" #include "cc/tiles/tile_manager.h" #include "components/viz/common/resources/resource_sizes.h" diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h index aab93183734..993fcdc1c30 100644 --- a/chromium/cc/tiles/tile_draw_info.h +++ b/chromium/cc/tiles/tile_draw_info.h @@ -7,7 +7,7 @@ #include <memory> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/resources/resource_pool.h" #include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/resource_format_utils.h" diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index 8f076724eb5..48e78c00e11 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -18,9 +18,9 @@ #include "base/metrics/histogram.h" #include "base/numerics/safe_conversions.h" #include "base/optional.h" -#include "base/sys_info.h" +#include "base/system/sys_info.h" #include "base/threading/thread_checker.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" #include "cc/layers/picture_layer_impl.h" @@ -682,8 +682,6 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(), resource_pool_->resource_count()); - RasterColorSpace raster_color_space = client_->GetRasterColorSpace(); - std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue( client_->BuildRasterQueue(global_state_.tree_priority, RasterTilePriorityQueue::Type::ALL)); @@ -736,8 +734,7 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { DCHECK(prioritized_tile.should_decode_checkered_images_for_tile()); AddCheckeredImagesToDecodeQueue( - prioritized_tile, raster_color_space.color_space, - CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); continue; } @@ -793,15 +790,13 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { if (tile->raster_task_scheduled_with_checker_images() && prioritized_tile.should_decode_checkered_images_for_tile()) { AddCheckeredImagesToDecodeQueue( - prioritized_tile, raster_color_space.color_space, - CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); } } else { // Creating the raster task here will acquire resources, but // this resource usage has already been accounted for above. - auto raster_task = CreateRasterTask( - prioritized_tile, client_->GetRasterColorSpace(), &work_to_schedule); + auto raster_task = CreateRasterTask(prioritized_tile, &work_to_schedule); if (!raster_task) { continue; } @@ -841,8 +836,7 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { if (tile->draw_info().is_checker_imaged() || tile->raster_task_scheduled_with_checker_images()) { AddCheckeredImagesToDecodeQueue( - prioritized_tile, raster_color_space.color_space, - CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); } } @@ -899,7 +893,6 @@ void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw( void TileManager::PartitionImagesForCheckering( const PrioritizedTile& prioritized_tile, - const gfx::ColorSpace& raster_color_space, std::vector<DrawImage>* sync_decoded_images, std::vector<PaintImage>* checkered_images, const gfx::Rect* invalidated_rect, @@ -922,7 +915,7 @@ void TileManager::PartitionImagesForCheckering( (*image_to_frame_index)[image.stable_id()] = frame_index; DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(), - frame_index, raster_color_space); + frame_index); if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) checkered_images->push_back(draw_image.paint_image()); else @@ -932,7 +925,6 @@ void TileManager::PartitionImagesForCheckering( void TileManager::AddCheckeredImagesToDecodeQueue( const PrioritizedTile& prioritized_tile, - const gfx::ColorSpace& raster_color_space, CheckerImageTracker::DecodeType decode_type, CheckerImageTracker::ImageDecodeQueue* image_decode_queue) { Tile* tile = prioritized_tile.tile(); @@ -945,7 +937,7 @@ void TileManager::AddCheckeredImagesToDecodeQueue( size_t frame_index = client_->GetFrameIndexForImage( original_draw_image->paint_image(), tree); DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(), - frame_index, raster_color_space); + frame_index); if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) { image_decode_queue->emplace_back(draw_image.paint_image(), decode_type); } @@ -981,9 +973,6 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { graph_.Reset(); - gfx::ColorSpace raster_color_space = - client_->GetRasterColorSpace().color_space; - scoped_refptr<TileTask> required_for_activation_done_task = CreateTaskSetFinishedTask( &TileManager::DidFinishRunningTileTasksRequiredForActivation); @@ -1038,9 +1027,8 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) { std::vector<DrawImage> sync_decoded_images; std::vector<PaintImage> checkered_images; - PartitionImagesForCheckering(prioritized_tile, raster_color_space, - &sync_decoded_images, &checkered_images, - nullptr); + PartitionImagesForCheckering(prioritized_tile, &sync_decoded_images, + &checkered_images, nullptr); // Add the sync decoded images to |new_locked_images| so they can be added // to the task graph. @@ -1132,7 +1120,6 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { scoped_refptr<TileTask> TileManager::CreateRasterTask( const PrioritizedTile& prioritized_tile, - const RasterColorSpace& raster_color_space, PrioritizedWorkToSchedule* work_to_schedule) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "TileManager::CreateRasterTask"); @@ -1149,7 +1136,7 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(), &invalidated_rect); } - + const RasterColorSpace& raster_color_space = client_->GetRasterColorSpace(); bool partial_tile_decode = false; if (resource) { resource_content_id = tile->invalidated_id(); @@ -1180,8 +1167,8 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( base::flat_map<PaintImage::Id, size_t> image_id_to_current_frame_index; if (!skip_images) { PartitionImagesForCheckering( - prioritized_tile, raster_color_space.color_space, &sync_decoded_images, - &checkered_images, partial_tile_decode ? &invalidated_rect : nullptr, + prioritized_tile, &sync_decoded_images, &checkered_images, + partial_tile_decode ? &invalidated_rect : nullptr, &image_id_to_current_frame_index); } @@ -1243,7 +1230,6 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( } PlaybackImageProvider image_provider(image_controller_.cache(), - raster_color_space.color_space, std::move(settings)); playback_settings.raster_color_space = raster_color_space; @@ -1301,7 +1287,7 @@ void TileManager::OnRasterTaskCompleted( // Once raster is done, allow the resource to be exported to the display // compositor, by giving it a ResourceId. - resource_pool_->PrepareForExport(resource); + bool exported = resource_pool_->PrepareForExport(resource); // In SMOOTHNESS_TAKES_PRIORITY mode, we wait for GPU work to complete for a // tile before setting it as ready to draw. @@ -1312,11 +1298,16 @@ void TileManager::OnRasterTaskCompleted( } TileDrawInfo& draw_info = tile->draw_info(); - bool needs_swizzle = raster_buffer_provider_->IsResourceSwizzleRequired(); - bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied(); - draw_info.SetResource(std::move(resource), - raster_task_was_scheduled_with_checker_images, - needs_swizzle, is_premultiplied); + if (exported) { + bool needs_swizzle = raster_buffer_provider_->IsResourceSwizzleRequired(); + bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied(); + draw_info.SetResource(std::move(resource), + raster_task_was_scheduled_with_checker_images, + needs_swizzle, is_premultiplied); + } else { + resource_pool_->ReleaseResource(std::move(resource)); + draw_info.set_oom(); + } if (raster_task_was_scheduled_with_checker_images) num_of_tiles_with_checker_images_++; diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h index e475cdf52b0..ac58ccfdc99 100644 --- a/chromium/cc/tiles/tile_manager.h +++ b/chromium/cc/tiles/tile_manager.h @@ -139,6 +139,9 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { ~TileManager() override; // Assigns tile memory and schedules work to prepare tiles for drawing. + // This step occurs after Commit and at most once per BeginFrame. It can be + // called on its own, that is, outside of Commit. + // // - Runs client_->NotifyReadyToActivate() when all tiles required for // activation are prepared, or failed to prepare due to OOM. // - Runs client_->NotifyReadyToDraw() when all tiles required draw are @@ -201,10 +204,12 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { // The raster here never really happened, cuz tests. So just add an // arbitrary sync token. if (resource.gpu_backing()) { + resource.gpu_backing()->mailbox = gpu::Mailbox::Generate(); resource.gpu_backing()->mailbox_sync_token.Set( gpu::GPU_IO, gpu::CommandBufferId::FromUnsafeValue(1), 1); } - resource_pool_->PrepareForExport(resource); + bool exported = resource_pool_->PrepareForExport(resource); + DCHECK(exported); draw_info.SetResource(std::move(resource), false, false, false); draw_info.set_resource_ready_for_draw(); } @@ -345,7 +350,6 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile); scoped_refptr<TileTask> CreateRasterTask( const PrioritizedTile& prioritized_tile, - const RasterColorSpace& raster_color_space, PrioritizedWorkToSchedule* work_to_schedule); std::unique_ptr<EvictionTilePriorityQueue> @@ -378,14 +382,12 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { void PartitionImagesForCheckering( const PrioritizedTile& prioritized_tile, - const gfx::ColorSpace& raster_color_space, std::vector<DrawImage>* sync_decoded_images, std::vector<PaintImage>* checkered_images, const gfx::Rect* invalidated_rect, base::flat_map<PaintImage::Id, size_t>* image_to_frame_index = nullptr); void AddCheckeredImagesToDecodeQueue( const PrioritizedTile& prioritized_tile, - const gfx::ColorSpace& raster_color_space, CheckerImageTracker::DecodeType decode_type, CheckerImageTracker::ImageDecodeQueue* image_decode_queue); diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index 6c7fe87703b..7fbe4f370dd 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -2169,6 +2169,91 @@ TEST_F(TileManagerTest, PartialRasterSuccessfullyDisabled) { RunPartialRasterCheck(TakeHostImpl(), false /* partial_raster_enabled */); } +class InvalidResourceRasterBufferProvider + : public FakeRasterBufferProviderImpl { + public: + std::unique_ptr<RasterBuffer> AcquireBufferForRaster( + const ResourcePool::InUsePoolResource& resource, + uint64_t resource_content_id, + uint64_t previous_content_id) override { + if (!resource.gpu_backing()) { + auto backing = std::make_unique<StubGpuBacking>(); + // Don't set a mailbox to signal invalid resource. + backing->texture_target = 5; + resource.set_gpu_backing(std::move(backing)); + } + return std::make_unique<FakeRasterBuffer>(); + } + + private: + class StubGpuBacking : public ResourcePool::GpuBacking { + public: + void OnMemoryDump( + base::trace_event::ProcessMemoryDump* pmd, + const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid, + uint64_t tracing_process_id, + int importance) const override {} + }; + + class FakeRasterBuffer : public RasterBuffer { + public: + void Playback(const RasterSource* raster_source, + const gfx::Rect& raster_full_rect, + const gfx::Rect& raster_dirty_rect, + uint64_t new_content_id, + const gfx::AxisTransform2d& transform, + const RasterSource::PlaybackSettings& playback_settings, + const GURL& url) override {} + }; +}; + +class InvalidResourceTileManagerTest : public TileManagerTest { + protected: + std::unique_ptr<LayerTreeFrameSink> CreateLayerTreeFrameSink() override { + return FakeLayerTreeFrameSink::Create3d(); + } +}; + +TEST_F(InvalidResourceTileManagerTest, InvalidResource) { + auto* tile_manager = host_impl()->tile_manager(); + InvalidResourceRasterBufferProvider raster_buffer_provider; + tile_manager->SetRasterBufferProviderForTesting(&raster_buffer_provider); + + gfx::Size size(10, 12); + FakePictureLayerTilingClient tiling_client; + tiling_client.SetTileSize(size); + + std::unique_ptr<PictureLayerImpl> layer = PictureLayerImpl::Create( + host_impl()->active_tree(), 1, Layer::LayerMaskType::NOT_MASK); + layer->set_contributes_to_drawn_render_surface(true); + + auto* tiling = layer->picture_layer_tiling_set()->AddTiling( + gfx::AxisTransform2d(), FakeRasterSource::CreateFilled(size)); + tiling->set_resolution(HIGH_RESOLUTION); + tiling->CreateAllTilesForTesting(); + tiling->SetTilePriorityRectsForTesting(gfx::Rect(size), // Visible rect. + gfx::Rect(size), // Skewport rect. + gfx::Rect(size), // Soon rect. + gfx::Rect(size)); // Eventually rect. + + base::RunLoop run_loop; + EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted()) + .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); })); + tile_manager->PrepareTiles(host_impl()->global_tile_state()); + run_loop.Run(); + tile_manager->CheckForCompletedTasks(); + + Tile* tile = tiling->TileAt(0, 0); + ASSERT_TRUE(tile); + // The tile in the tiling was rastered, but didn't get a resource. + EXPECT_TRUE(tile->draw_info().IsReadyToDraw()); + EXPECT_EQ(TileDrawInfo::OOM_MODE, tile->draw_info().mode()); + + // Ensure that the host impl doesn't outlive |raster_buffer_provider|. + layer = nullptr; + TakeHostImpl(); +} + // FakeRasterBufferProviderImpl that allows us to mock ready to draw // functionality. class MockReadyToDrawRasterBufferProviderImpl @@ -3280,9 +3365,9 @@ TEST_F(DecodedImageTrackerTileManagerTest, DecodedImageTrackerDropsLocksOnUse) { // Add the images to our decoded_image_tracker. host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode( - image1, gfx::ColorSpace(), base::DoNothing()); + image1, base::DoNothing()); host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode( - image2, gfx::ColorSpace(), base::DoNothing()); + image2, base::DoNothing()); EXPECT_EQ(0u, host_impl() ->tile_manager() ->decoded_image_tracker() diff --git a/chromium/cc/tiles/tile_priority.cc b/chromium/cc/tiles/tile_priority.cc index 0efe51e5972..7898163053e 100644 --- a/chromium/cc/tiles/tile_priority.cc +++ b/chromium/cc/tiles/tile_priority.cc @@ -5,7 +5,7 @@ #include "cc/tiles/tile_priority.h" #include "base/numerics/safe_conversions.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" #include "cc/base/math_util.h" diff --git a/chromium/cc/tiles/tile_priority.h b/chromium/cc/tiles/tile_priority.h index 15746de6506..015b0c422ea 100644 --- a/chromium/cc/tiles/tile_priority.h +++ b/chromium/cc/tiles/tile_priority.h @@ -12,7 +12,7 @@ #include <memory> #include <string> -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/cc_export.h" namespace base { diff --git a/chromium/cc/trees/clip_node.cc b/chromium/cc/trees/clip_node.cc index c1a73a952c5..edeba2af9d0 100644 --- a/chromium/cc/trees/clip_node.cc +++ b/chromium/cc/trees/clip_node.cc @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/trace_event/trace_event_argument.h" +#include "cc/trees/clip_node.h" + #include "cc/base/math_util.h" #include "cc/layers/layer.h" -#include "cc/trees/clip_node.h" #include "cc/trees/property_tree.h" +#include "base/trace_event/traced_value.h" + namespace cc { ClipNode::ClipNode() diff --git a/chromium/cc/trees/clip_node.h b/chromium/cc/trees/clip_node.h index 5620f9d020c..54e554719e4 100644 --- a/chromium/cc/trees/clip_node.h +++ b/chromium/cc/trees/clip_node.h @@ -9,6 +9,7 @@ #include "base/optional.h" #include "cc/cc_export.h" #include "cc/trees/clip_expander.h" +#include "cc/trees/property_tree.h" #include "ui/gfx/geometry/rect_f.h" namespace base { diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc index 925069e0643..dded3612e22 100644 --- a/chromium/cc/trees/damage_tracker.cc +++ b/chromium/cc/trees/damage_tracker.cc @@ -64,7 +64,7 @@ void DamageTracker::UpdateDamageTracking( // // - This algorithm requires that descendant surfaces compute their damage // before ancestor surfaces. Further, since contributing surfaces with - // background filters can expand the damage caused by contributors + // backdrop filters can expand the damage caused by contributors // underneath them (that is, before them in draw order), the exact damage // caused by these contributors must be computed before computing the damage // caused by the contributing surface. This is implemented by visiting @@ -338,11 +338,11 @@ void DamageTracker::ExpandDamageInsideRectWithFilters( if (!is_valid_rect || damage_rect.IsEmpty()) return; - // Compute the pixels in the background of the surface that could be affected + // Compute the pixels in the backdrop of the surface that could be affected // by the damage in the content below. gfx::Rect expanded_damage_rect = filters.MapRect(damage_rect, SkMatrix::I()); - // Restrict it to the rectangle in which the background filter is shown. + // Restrict it to the rectangle in which the backdrop filter is shown. expanded_damage_rect.Intersect(pre_filter_rect); damage_for_this_update_.Union(expanded_damage_rect); @@ -452,17 +452,16 @@ void DamageTracker::AccumulateDamageFromRenderSurface( } } - // If the layer has a background filter, this may cause pixels in our surface + // If the layer has a backdrop filter, this may cause pixels in our surface // to be expanded, so we will need to expand any damage at or below this // layer. We expand the damage from this layer too, as we need to readback // those pixels from the surface with only the contents of layers below this // one in them. This means we need to redraw any pixels in the surface being // used for the blur in this layer this frame. - const FilterOperations& background_filters = - render_surface->BackgroundFilters(); - if (background_filters.HasFilterThatMovesPixels()) { + const FilterOperations& backdrop_filters = render_surface->BackdropFilters(); + if (backdrop_filters.HasFilterThatMovesPixels()) { ExpandDamageInsideRectWithFilters(surface_rect_in_target_space, - background_filters); + backdrop_filters); } // True if any changes from contributing render surface. diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc index d4c755877c1..03d1e971600 100644 --- a/chromium/cc/trees/damage_tracker_unittest.cc +++ b/chromium/cc/trees/damage_tracker_unittest.cc @@ -924,7 +924,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForHighDPIImageFilter) { EXPECT_EQ(expected_child_damage_rect, child_damage_rect); } -TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { +TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->test_properties()->children[0]; LayerImpl* child2 = root->test_properties()->children[1]; @@ -937,13 +937,13 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { // Setting the filter will damage the whole surface. ClearDamageForAllSurfaces(root); - child1->test_properties()->background_filters = filters; + child1->test_properties()->backdrop_filters = filters; child1->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; EmulateDrawingOneFrame(root); // CASE 1: Setting the update rect should cause the corresponding damage to - // the surface, blurred based on the size of the child's background + // the surface, blurred based on the size of the child's backdrop // blur filter. Note that child1's render surface has a size of // 206x208 due to contributions from grand_child1 and grand_child2. ClearDamageForAllSurfaces(root); @@ -964,7 +964,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString()); // CASE 2: Setting the update rect should cause the corresponding damage to - // the surface, blurred based on the size of the child's background + // the surface, blurred based on the size of the child's backdrop // blur filter. Since the damage extends to the right/bottom outside // of the blurred layer, only the left/top should end up expanded. ClearDamageForAllSurfaces(root); @@ -1053,7 +1053,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { // CASE 7: No changes, so should not damage the surface. ClearDamageForAllSurfaces(root); - // We want to make sure that the background filter doesn't cause empty damage + // We want to make sure that the backdrop filter doesn't cause empty damage // to get expanded. We position child1 so that an expansion of the empty rect // would have non-empty intersection with child1 in its target space (root // space). @@ -1791,7 +1791,7 @@ TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(5.f)); root->SetDrawsContent(true); - root->test_properties()->background_filters = filters; + root->test_properties()->backdrop_filters = filters; // Really far left. child1->SetPosition(gfx::PointF(std::numeric_limits<int>::min() + 100, 0)); @@ -1917,7 +1917,7 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(5.f)); child1->SetDrawsContent(true); - child1->test_properties()->background_filters = filters; + child1->test_properties()->backdrop_filters = filters; // Really far left. grandchild1->SetPosition( diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc index 7c9b86cb096..ef8086d01d5 100644 --- a/chromium/cc/trees/draw_property_utils.cc +++ b/chromium/cc/trees/draw_property_utils.cc @@ -457,9 +457,14 @@ static inline bool LayerShouldBeSkippedInternal( LayerType* layer, const TransformTree& transform_tree, const EffectTree& effect_tree) { + // TODO(enne): remove temporary CHECKs once http://crbug.com/898668 is fixed. + CHECK_NE(layer->transform_tree_index(), TransformTree::kInvalidNodeId); const TransformNode* transform_node = transform_tree.Node(layer->transform_tree_index()); + CHECK(transform_node); + CHECK_NE(layer->effect_tree_index(), EffectTree::kInvalidNodeId); const EffectNode* effect_node = effect_tree.Node(layer->effect_tree_index()); + CHECK(effect_node); if (effect_node->has_render_surface && effect_node->subtree_has_copy_request) return false; @@ -725,6 +730,9 @@ bool LayerShouldBeSkippedForDrawPropertiesComputation( LayerImpl* layer, const TransformTree& transform_tree, const EffectTree& effect_tree) { + // TODO(enne): remove temporary CHECKs once http://crbug.com/898668 is fixed. + CHECK(layer); + CHECK(layer->layer_tree_impl()); return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree); } @@ -732,6 +740,11 @@ bool LayerShouldBeSkippedForDrawPropertiesComputation( Layer* layer, const TransformTree& transform_tree, const EffectTree& effect_tree) { + // TODO(enne): remove temporary CHECKs once http://crbug.com/898668 is fixed. + CHECK(layer); + CHECK(layer->layer_tree_host()); + CHECK_EQ(layer->layer_tree_host()->property_trees()->sequence_number, + layer->property_tree_sequence_number()); return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree); } diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc index 4bc3274497e..b0138a10a4a 100644 --- a/chromium/cc/trees/effect_node.cc +++ b/chromium/cc/trees/effect_node.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/trace_event/trace_event_argument.h" -#include "cc/layers/layer.h" #include "cc/trees/effect_node.h" +#include "base/trace_event/traced_value.h" +#include "cc/layers/layer.h" #include "cc/trees/property_tree.h" namespace cc { @@ -50,7 +50,7 @@ bool EffectNode::operator==(const EffectNode& other) const { cache_render_surface == other.cache_render_surface && has_copy_request == other.has_copy_request && filters == other.filters && - background_filters == other.background_filters && + backdrop_filters == other.backdrop_filters && filters_origin == other.filters_origin && blend_mode == other.blend_mode && surface_contents_scale == other.surface_contents_scale && diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h index 72d0c062e17..0f8bf3399a6 100644 --- a/chromium/cc/trees/effect_node.h +++ b/chromium/cc/trees/effect_node.h @@ -39,7 +39,7 @@ struct CC_EXPORT EffectNode { float screen_space_opacity; FilterOperations filters; - FilterOperations background_filters; + FilterOperations backdrop_filters; float backdrop_filter_quality; gfx::PointF filters_origin; diff --git a/chromium/cc/trees/element_id.cc b/chromium/cc/trees/element_id.cc index 0603ba726c7..95c79a7b19c 100644 --- a/chromium/cc/trees/element_id.cc +++ b/chromium/cc/trees/element_id.cc @@ -9,7 +9,7 @@ #include <ostream> #include "base/strings/stringprintf.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "base/values.h" namespace cc { diff --git a/chromium/cc/trees/layer_tree_frame_sink.h b/chromium/cc/trees/layer_tree_frame_sink.h index edbdd247f15..15b3568a8cf 100644 --- a/chromium/cc/trees/layer_tree_frame_sink.h +++ b/chromium/cc/trees/layer_tree_frame_sink.h @@ -105,8 +105,11 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter, // For successful swaps, the implementation must call // DidReceiveCompositorFrameAck() asynchronously when the frame has been - // processed in order to unthrottle the next frame. - virtual void SubmitCompositorFrame(viz::CompositorFrame frame) = 0; + // processed in order to unthrottle the next frame. |show_hit_test_borders| + // controls whether viz will insert debug borders over hit-test data and is + // passed from LayerTreeDebugState. + virtual void SubmitCompositorFrame(viz::CompositorFrame frame, + bool show_hit_test_borders) = 0; // Signals that a BeginFrame issued by the viz::BeginFrameSource provided to // the client did not lead to a CompositorFrame submission. @@ -117,6 +120,10 @@ class CC_EXPORT LayerTreeFrameSink : public viz::SharedBitmapReporter, const viz::SharedBitmapId& id) override = 0; void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override = 0; + // Ensure next CompositorFrame is submitted to a new surface. Only used when + // surface synchronization is off. + virtual void ForceAllocateNewId() {} + protected: class ContextLostForwarder; diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h index 87fc6b8b11e..b89a6e738c4 100644 --- a/chromium/cc/trees/layer_tree_frame_sink_client.h +++ b/chromium/cc/trees/layer_tree_frame_sink_client.h @@ -68,6 +68,9 @@ class CC_EXPORT LayerTreeFrameSinkClient { // viz::ContextProviders) must be recreated. virtual void DidLoseLayerTreeFrameSink() = 0; + // Notification that the client does not need a new BeginFrame. + virtual void DidNotNeedBeginFrame() = 0; + // For SynchronousCompositor (WebView) to ask the layer compositor to submit // a new CompositorFrame synchronously. virtual void OnDraw(const gfx::Transform& transform, diff --git a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc index 355b818c48b..cd40a54d467 100644 --- a/chromium/cc/trees/layer_tree_frame_sink_unittest.cc +++ b/chromium/cc/trees/layer_tree_frame_sink_unittest.cc @@ -28,7 +28,8 @@ class StubLayerTreeFrameSink : public LayerTreeFrameSink { std::move(compositor_task_runner), nullptr) {} - void SubmitCompositorFrame(viz::CompositorFrame frame) override { + void SubmitCompositorFrame(viz::CompositorFrame frame, + bool show_hit_test_borders) override { client_->DidReceiveCompositorFrameAck(); } void DidNotProduceFrame(const viz::BeginFrameAck& ack) override {} diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index ecee592a25f..01ec4196d06 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -28,7 +28,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/timer/elapsed_timer.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "build/build_config.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" @@ -120,7 +120,7 @@ LayerTreeHost::LayerTreeHost(InitParams params, CompositorMode mode) content_source_id_(0), event_listener_properties_(), mutator_host_(params.mutator_host), - defer_commits_weak_ptr_factory_(this) { + defer_main_frame_update_weak_ptr_factory_(this) { DCHECK(task_graph_runner_); DCHECK(!settings_.enable_checker_imaging || image_worker_task_runner_); @@ -173,15 +173,15 @@ void LayerTreeHost::InitializeProxy(std::unique_ptr<Proxy> proxy) { proxy_ = std::move(proxy); proxy_->Start(); - UpdateDeferCommitsInternal(); + UpdateDeferMainFrameUpdateInternal(); mutator_host_->SetSupportsScrollAnimations(proxy_->SupportsImplScrolling()); } LayerTreeHost::~LayerTreeHost() { // Track when we're inside a main frame to see if compositor is being - // destroyed midway which causes a crash. crbug.com/654672 - DCHECK(!inside_main_frame_); + // destroyed midway which causes a crash. crbug.com/895883 + CHECK(!inside_main_frame_); TRACE_EVENT0("cc", "LayerTreeHost::~LayerTreeHost"); // Clear any references into the LayerTreeHost. @@ -277,8 +277,8 @@ const LayerTreeDebugState& LayerTreeHost::GetDebugState() const { return debug_state_; } -void LayerTreeHost::RequestMainFrameUpdate() { - client_->UpdateLayerTreeHost(); +void LayerTreeHost::RequestMainFrameUpdate(bool record_main_frame_metrics) { + client_->UpdateLayerTreeHost(record_main_frame_metrics); } // This function commits the LayerTreeHost to an impl tree. When modifying @@ -312,6 +312,7 @@ void LayerTreeHost::FinishCommitOnImplThread( pending_presentation_time_callbacks_.push_back(base::DoNothing()); sync_tree->AddPresentationCallbacks( std::move(pending_presentation_time_callbacks_)); + pending_presentation_time_callbacks_.clear(); if (needs_full_tree_sync_) TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree); @@ -376,22 +377,14 @@ void LayerTreeHost::FinishCommitOnImplThread( // Dump property trees and layers if run with: // --vmodule=layer_tree_host=3 if (VLOG_IS_ON(3)) { - VLOG(3) << "After finishing commit on impl, the sync tree:"; - // Because the property tree and layer list output can be verbose, the VLOG - // output is split by line to avoid line buffer limits on android. - VLOG(3) << "property trees:"; std::string property_trees; base::JSONWriter::WriteWithOptions( *sync_tree->property_trees()->AsTracedValue()->ToBaseValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &property_trees); - std::stringstream property_trees_stream(property_trees); - for (std::string line; std::getline(property_trees_stream, line);) - VLOG(3) << line; - - VLOG(3) << "layers:"; - std::stringstream layers_stream(host_impl->LayerListAsJson()); - for (std::string line; std::getline(layers_stream, line);) - VLOG(3) << line; + VLOG(3) << "After finishing commit on impl, the sync tree:" + << "\nproperty_trees:\n" + << property_trees << "\nlayers:\n" + << host_impl->LayerListAsJson(); } } @@ -444,11 +437,11 @@ void LayerTreeHost::WillCommit() { } } - -void LayerTreeHost::UpdateDeferCommitsInternal() { - proxy_->SetDeferCommits(defer_commits_count_ > 0 || - (settings_.enable_surface_synchronization && - !local_surface_id_from_parent_.is_valid())); +void LayerTreeHost::UpdateDeferMainFrameUpdateInternal() { + proxy_->SetDeferMainFrameUpdate( + defer_main_frame_update_count_ > 0 || + (settings_.enable_surface_synchronization && + !local_surface_id_allocation_from_parent_.IsValid())); } bool LayerTreeHost::IsUsingLayerLists() const { @@ -534,23 +527,24 @@ void LayerTreeHost::DidLoseLayerTreeFrameSink() { SetNeedsCommit(); } -ScopedDeferCommits::ScopedDeferCommits(LayerTreeHost* host) - : host_(host->defer_commits_weak_ptr_factory_.GetWeakPtr()) { - host->defer_commits_count_++; - host->UpdateDeferCommitsInternal(); +ScopedDeferMainFrameUpdate::ScopedDeferMainFrameUpdate(LayerTreeHost* host) + : host_(host->defer_main_frame_update_weak_ptr_factory_.GetWeakPtr()) { + host->defer_main_frame_update_count_++; + host->UpdateDeferMainFrameUpdateInternal(); } -ScopedDeferCommits::~ScopedDeferCommits() { +ScopedDeferMainFrameUpdate::~ScopedDeferMainFrameUpdate() { LayerTreeHost* host = host_.get(); if (host) { - DCHECK_GT(host->defer_commits_count_, 0u); - if (--host->defer_commits_count_ == 0) - host->UpdateDeferCommitsInternal(); + DCHECK_GT(host->defer_main_frame_update_count_, 0u); + if (--host->defer_main_frame_update_count_ == 0) + host->UpdateDeferMainFrameUpdateInternal(); } } -std::unique_ptr<ScopedDeferCommits> LayerTreeHost::DeferCommits() { - return std::make_unique<ScopedDeferCommits>(this); +std::unique_ptr<ScopedDeferMainFrameUpdate> +LayerTreeHost::DeferMainFrameUpdate() { + return std::make_unique<ScopedDeferMainFrameUpdate>(this); } DISABLE_CFI_PERF @@ -656,7 +650,7 @@ void LayerTreeHost::LayoutAndUpdateLayers() { DCHECK(IsSingleThreaded()); // This function is only valid when not using the scheduler. DCHECK(!settings_.single_thread_proxy_scheduler); - RequestMainFrameUpdate(); + RequestMainFrameUpdate(false /* record_main_frame_metrics */); UpdateLayers(); } @@ -756,8 +750,6 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { // and SlimmingPaintV2. if (!IsUsingLayerLists()) { TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::BuildPropertyTrees"); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees"); Layer* root_scroll = PropertyTreeBuilder::FindFirstScrollableLayer(root_layer); Layer* page_scale_layer = viewport_layers_.page_scale.get(); @@ -813,33 +805,27 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { // --vmodule=layer_tree_host=3 // This only prints output for the renderer. if (VLOG_IS_ON(3) && GetClientNameForMetrics() == std::string("Renderer")) { - VLOG(3) << "After updating layers on the main thread:"; - // Because the property tree and layer list output can be verbose, the VLOG - // output is split by line to avoid line buffer limits on android. - VLOG(3) << "property trees:"; std::string property_trees; base::JSONWriter::WriteWithOptions( *property_trees_.AsTracedValue()->ToBaseValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &property_trees); - std::stringstream property_trees_stream(property_trees); - for (std::string line; std::getline(property_trees_stream, line);) - VLOG(3) << line; - - VLOG(3) << "layers:"; + std::ostringstream layers; for (auto* layer : *this) { - VLOG(3) << " layer id " << layer->id(); - VLOG(3) << " element_id: " << layer->element_id(); - VLOG(3) << " bounds: " << layer->bounds().ToString(); - VLOG(3) << " opacity: " << layer->opacity(); - VLOG(3) << " position: " << layer->position().ToString(); - VLOG(3) << " draws_content: " << layer->DrawsContent(); - VLOG(3) << " scrollable: " << layer->scrollable(); - VLOG(3) << " contents_opaque: " << layer->contents_opaque(); - VLOG(3) << " transform_tree_index: " << layer->transform_tree_index(); - VLOG(3) << " clip_tree_index: " << layer->clip_tree_index(); - VLOG(3) << " effect_tree_index: " << layer->effect_tree_index(); - VLOG(3) << " scroll_tree_index: " << layer->scroll_tree_index(); + layers << "\n layer id " << layer->id(); + layers << "\n element_id: " << layer->element_id(); + layers << "\n bounds: " << layer->bounds().ToString(); + layers << "\n opacity: " << layer->opacity(); + layers << "\n position: " << layer->position().ToString(); + layers << "\n draws_content: " << layer->DrawsContent(); + layers << "\n scrollable: " << layer->scrollable(); + layers << "\n contents_opaque: " << layer->contents_opaque(); + layers << "\n transform_tree_index: " << layer->transform_tree_index(); + layers << "\n clip_tree_index: " << layer->clip_tree_index(); + layers << "\n effect_tree_index: " << layer->effect_tree_index(); + layers << "\n scroll_tree_index: " << layer->scroll_tree_index(); } + VLOG(3) << "After updating layers on the main thread:\nproperty trees:\n" + << property_trees << "\nlayers:" << layers.str(); } bool painted_content_has_slow_paths = false; @@ -869,23 +855,25 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { return did_paint_content; } -void LayerTreeHost::ApplyViewportDeltas(const ScrollAndScaleSet& info) { - gfx::Vector2dF inner_viewport_scroll_delta; +void LayerTreeHost::ApplyViewportChanges(const ScrollAndScaleSet& info) { + gfx::ScrollOffset inner_viewport_scroll_delta; if (info.inner_viewport_scroll.element_id) inner_viewport_scroll_delta = info.inner_viewport_scroll.scroll_delta; if (inner_viewport_scroll_delta.IsZero() && info.page_scale_delta == 1.f && - info.elastic_overscroll_delta.IsZero() && !info.top_controls_delta) + info.elastic_overscroll_delta.IsZero() && !info.top_controls_delta && + !info.browser_controls_constraint_changed && + !info.scroll_gesture_did_end) { return; + } // Preemptively apply the scroll offset and scale delta here before sending // it to the client. If the client comes back and sets it to the same // value, then the layer can early out without needing a full commit. if (viewport_layers_.inner_viewport_scroll) { viewport_layers_.inner_viewport_scroll->SetScrollOffsetFromImplSide( - gfx::ScrollOffsetWithDelta( - viewport_layers_.inner_viewport_scroll->CurrentScrollOffset(), - inner_viewport_scroll_delta)); + viewport_layers_.inner_viewport_scroll->CurrentScrollOffset() + + inner_viewport_scroll_delta); } ApplyPageScaleDeltaFromImplSide(info.page_scale_delta); @@ -895,7 +883,8 @@ void LayerTreeHost::ApplyViewportDeltas(const ScrollAndScaleSet& info) { // may be translated appropriately. client_->ApplyViewportChanges( {inner_viewport_scroll_delta, info.elastic_overscroll_delta, - info.page_scale_delta, info.top_controls_delta}); + info.page_scale_delta, info.top_controls_delta, + info.browser_controls_constraint, info.scroll_gesture_did_end}); SetNeedsUpdateLayers(); } @@ -925,8 +914,8 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { Layer* layer = LayerByElementId(info->scrolls[i].element_id); if (!layer) continue; - layer->SetScrollOffsetFromImplSide(gfx::ScrollOffsetWithDelta( - layer->CurrentScrollOffset(), info->scrolls[i].scroll_delta)); + layer->SetScrollOffsetFromImplSide(layer->CurrentScrollOffset() + + info->scrolls[i].scroll_delta); SetNeedsUpdateLayers(); } for (size_t i = 0; i < info->scrollbars.size(); ++i) { @@ -940,7 +929,7 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { // This needs to happen after scroll deltas have been sent to prevent top // controls from clamping the layout viewport both on the compositor and // on the main thread. - ApplyViewportDeltas(*info); + ApplyViewportChanges(*info); RecordWheelAndTouchScrollingCount(*info); } @@ -1078,6 +1067,13 @@ void LayerTreeHost::RegisterViewportLayers(const ViewportLayers& layers) { viewport_layers_.outer_viewport_scroll = layers.outer_viewport_scroll; } +void LayerTreeHost::RegisterViewportPropertyIds( + const ViewportPropertyIds& ids) { + DCHECK(!viewport_layers_.inner_viewport_scroll); + DCHECK(IsUsingLayerLists()); + viewport_property_ids_ = ids; +} + void LayerTreeHost::RegisterSelection(const LayerSelection& selection) { if (selection_ == selection) return; @@ -1140,8 +1136,10 @@ void LayerTreeHost::SetEventListenerProperties( void LayerTreeHost::SetViewportSizeAndScale( const gfx::Size& device_viewport_size, float device_scale_factor, - const viz::LocalSurfaceId& local_surface_id_from_parent) { - SetLocalSurfaceIdFromParent(local_surface_id_from_parent); + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent) { + SetLocalSurfaceIdAllocationFromParent( + local_surface_id_allocation_from_parent); bool changed = false; if (device_viewport_size_ != device_viewport_size) { @@ -1170,7 +1168,7 @@ void LayerTreeHost::SetViewportSizeAndScale( // be. CHECK(!has_pushed_local_surface_id_from_parent_ || new_local_surface_id_request_ || - !local_surface_id_from_parent_.is_valid()); + !local_surface_id_allocation_from_parent_.IsValid()); #endif } } @@ -1267,29 +1265,48 @@ void LayerTreeHost::SetRasterColorSpace( this, [](Layer* layer) { layer->SetNeedsDisplay(); }); } +void LayerTreeHost::SetExternalPageScaleFactor(float page_scale_factor) { + if (external_page_scale_factor_ == page_scale_factor) + return; + + external_page_scale_factor_ = page_scale_factor; + SetNeedsCommit(); +} + void LayerTreeHost::SetContentSourceId(uint32_t id) { content_source_id_ = id; } -void LayerTreeHost::SetLocalSurfaceIdFromParent( - const viz::LocalSurfaceId& local_surface_id_from_parent) { - if (local_surface_id_from_parent_.parent_sequence_number() == +void LayerTreeHost::SetLocalSurfaceIdAllocationFromParent( + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent) { + const viz::LocalSurfaceId& local_surface_id_from_parent = + local_surface_id_allocation_from_parent.local_surface_id(); + const viz::LocalSurfaceId& current_local_surface_id_from_parent = + local_surface_id_allocation_from_parent_.local_surface_id(); + if (current_local_surface_id_from_parent.parent_sequence_number() == local_surface_id_from_parent.parent_sequence_number() && - local_surface_id_from_parent_.embed_token() == + current_local_surface_id_from_parent.embed_token() == local_surface_id_from_parent.embed_token()) { return; } + // If the viz::LocalSurfaceId is valid but the allocation time is invalid then + // this API is not being used correctly. + DCHECK_EQ(local_surface_id_from_parent.is_valid(), + local_surface_id_allocation_from_parent.IsValid()); + TRACE_EVENT_WITH_FLOW2( TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), "LocalSurfaceId.Submission.Flow", TRACE_ID_GLOBAL(local_surface_id_from_parent.submission_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "SetLocalSurfaceIdFromParent", "local_surface_id", - local_surface_id_from_parent.ToString()); - local_surface_id_from_parent_ = local_surface_id_from_parent; + "SetLocalSurfaceAllocationIdFromParent", "local_surface_id_allocation", + local_surface_id_allocation_from_parent.ToString()); + local_surface_id_allocation_from_parent_ = + local_surface_id_allocation_from_parent; has_pushed_local_surface_id_from_parent_ = false; - UpdateDeferCommitsInternal(); + UpdateDeferMainFrameUpdateInternal(); SetNeedsCommit(); } @@ -1302,7 +1319,7 @@ void LayerTreeHost::RequestNewLocalSurfaceId() { // viz::LocalSurfaceId but that request will be deferred until we have a valid // viz::LocalSurfaceId from the parent. DCHECK(settings_.enable_surface_synchronization || - local_surface_id_from_parent_.is_valid()); + local_surface_id_allocation_from_parent_.IsValid()); if (new_local_surface_id_request_) return; new_local_surface_id_request_ = true; @@ -1412,14 +1429,10 @@ void LayerTreeHost::UpdateHudLayer(bool show_hud_info) { if (show_hud_info) { if (!hud_layer_.get()) hud_layer_ = HeadsUpDisplayLayer::Create(); - - gfx::Size device_viewport_in_layout_pixels = - gfx::Size(device_viewport_size_.width() / device_scale_factor_, - device_viewport_size_.height() / device_scale_factor_); - hud_layer_->SetBounds(device_viewport_in_layout_pixels); - if (root_layer_.get() && !hud_layer_->parent()) root_layer_->AddChild(hud_layer_); + hud_layer_->UpdateLocationAndSize(device_viewport_size_, + device_scale_factor_); } else if (hud_layer_.get()) { hud_layer_->RemoveFromParent(); hud_layer_ = nullptr; @@ -1483,6 +1496,8 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { tree_impl->ClearViewportLayers(); } + tree_impl->set_viewport_property_ids(viewport_property_ids_); + tree_impl->RegisterSelection(selection_); tree_impl->PushPageScaleFromMainThread( @@ -1499,6 +1514,7 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { tree_impl->elastic_overscroll()->PushPendingToActive(); tree_impl->SetRasterColorSpace(raster_color_space_id_, raster_color_space_); + tree_impl->SetExternalPageScaleFactor(external_page_scale_factor_); tree_impl->set_content_source_id(content_source_id_); @@ -1510,7 +1526,8 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { if (TakeNewLocalSurfaceIdRequest()) tree_impl->RequestNewLocalSurfaceId(); - tree_impl->SetLocalSurfaceIdFromParent(local_surface_id_from_parent_); + tree_impl->SetLocalSurfaceIdAllocationFromParent( + local_surface_id_allocation_from_parent_); has_pushed_local_surface_id_from_parent_ = true; if (pending_page_scale_animation_) { @@ -1518,6 +1535,9 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { std::move(pending_page_scale_animation_)); } + if (TakeForceSendMetadataRequest()) + tree_impl->RequestForceSendMetadata(); + tree_impl->set_has_ever_been_drawn(false); } @@ -1549,6 +1569,7 @@ void LayerTreeHost::RegisterElement(ElementId element_id, ElementListType list_type, Layer* layer) { element_layers_map_[element_id] = layer; + elements_in_property_trees_.insert(element_id); mutator_host_->RegisterElement(element_id, list_type); } @@ -1556,6 +1577,27 @@ void LayerTreeHost::UnregisterElement(ElementId element_id, ElementListType list_type) { mutator_host_->UnregisterElement(element_id, list_type); element_layers_map_.erase(element_id); + elements_in_property_trees_.erase(element_id); +} + +void LayerTreeHost::SetActiveRegisteredElementIds(const ElementIdSet& ids) { + DCHECK(IsUsingLayerLists()); + + // Unregister ids that should no longer be registered. + for (auto id_iter = elements_in_property_trees_.begin(); + id_iter != elements_in_property_trees_.end();) { + const auto& id = *(id_iter++); + if (!ids.count(id)) + UnregisterElement(id, ElementListType::ACTIVE); + } + + // Register new ids that were not already registered. + for (const auto& id : ids) { + if (!elements_in_property_trees_.count(id)) { + elements_in_property_trees_.insert(id); + mutator_host_->RegisterElement(id, ElementListType::ACTIVE); + } + } } static void SetElementIdForTesting(Layer* layer) { @@ -1577,6 +1619,10 @@ void LayerTreeHost::BuildPropertyTreesForTesting() { bool LayerTreeHost::IsElementInList(ElementId element_id, ElementListType list_type) const { + if (IsUsingLayerLists()) { + return list_type == ElementListType::ACTIVE && + elements_in_property_trees_.count(element_id); + } return list_type == ElementListType::ACTIVE && LayerByElementId(element_id); } @@ -1728,4 +1774,10 @@ void LayerTreeHost::SetRenderFrameObserver( proxy_->SetRenderFrameObserver(std::move(observer)); } +bool LayerTreeHost::TakeForceSendMetadataRequest() { + bool force_send_metadata_request = force_send_metadata_request_; + force_send_metadata_request_ = false; + return force_send_metadata_request; +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index d2cd6ed1f5b..d35269410a8 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -44,6 +44,7 @@ #include "cc/trees/swap_promise_manager.h" #include "cc/trees/target_property.h" #include "components/viz/common/resources/resource_format.h" +#include "components/viz/common/surfaces/local_surface_id_allocation.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/rect.h" @@ -72,12 +73,12 @@ class UkmRecorderFactory; struct RenderingStats; struct ScrollAndScaleSet; -// Returned from LayerTreeHost::DeferCommits. Automatically un-defers on +// Returned from LayerTreeHost::DeferMainFrameUpdate. Automatically un-defers on // destruction. -class CC_EXPORT ScopedDeferCommits { +class CC_EXPORT ScopedDeferMainFrameUpdate { public: - explicit ScopedDeferCommits(LayerTreeHost* host); - ~ScopedDeferCommits(); + explicit ScopedDeferMainFrameUpdate(LayerTreeHost* host); + ~ScopedDeferMainFrameUpdate(); private: base::WeakPtr<LayerTreeHost> host_; @@ -220,14 +221,16 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool CommitRequested() const; // Prevents the compositor from requesting main frame updates from the client - // until the ScopedDeferCommits object is destroyed, or StopDeferringCommits - // is called. - std::unique_ptr<ScopedDeferCommits> DeferCommits(); - - // Returns whether there are any outstanding ScopedDeferCommits, though - // commits may be deferred also when the local_surface_id_from_parent() is not - // valid. - bool defer_commits() const { return defer_commits_count_; } + // until the ScopedDeferMainFrameUpdate object is destroyed, or + // StopDeferringCommits is called. + std::unique_ptr<ScopedDeferMainFrameUpdate> DeferMainFrameUpdate(); + + // Returns whether there are any outstanding ScopedDeferMainFrameUpdate, + // though commits may be deferred also when the local_surface_id_from_parent() + // is not valid. + bool defer_main_frame_update() const { + return defer_main_frame_update_count_; + } // Synchronously performs a main frame update and layer updates. Used only in // single threaded mode when the compositor's internal scheduling is disabled. @@ -330,6 +333,16 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { return viewport_layers_.outer_viewport_scroll.get(); } + // Counterpart of ViewportLayers for CompositeAfterPaint which doesn't create + // viewport layers. + struct ViewportPropertyIds { + int page_scale_transform = TransformTree::kInvalidNodeId; + // TODO(crbug.com/909750): Switch other usages of viewport layers to + // property ids for CompositeAfterPaint. + }; + + void RegisterViewportPropertyIds(const ViewportPropertyIds&); + // Sets or gets the position of touch handles for a text selection. These are // submitted to the display compositor along with the Layer tree's contents // allowing it to present the selection handles. This is done because the @@ -359,10 +372,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { return event_listener_properties_[static_cast<size_t>(event_class)]; } - void SetViewportSizeAndScale( - const gfx::Size& device_viewport_size, - float device_scale_factor, - const viz::LocalSurfaceId& local_surface_id_from_parent); + void SetViewportSizeAndScale(const gfx::Size& device_viewport_size, + float device_scale_factor, + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent); void SetViewportVisibleRect(const gfx::Rect& visible_rect); @@ -409,10 +422,13 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // If this LayerTreeHost needs a valid viz::LocalSurfaceId then commits will // be deferred until a valid viz::LocalSurfaceId is provided. - void SetLocalSurfaceIdFromParent( - const viz::LocalSurfaceId& local_surface_id_from_parent); - const viz::LocalSurfaceId& local_surface_id_from_parent() const { - return local_surface_id_from_parent_; + void SetLocalSurfaceIdAllocationFromParent( + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent); + + const viz::LocalSurfaceIdAllocation& local_surface_id_allocation_from_parent() + const { + return local_surface_id_allocation_from_parent_; } // Requests the allocation of a new LocalSurfaceId on the compositor thread. @@ -430,6 +446,20 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { return raster_color_space_; } + // This layer tree may be embedded in a hierarchy that has page scale + // factor controlled at the top level. We represent that scale 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. + void SetExternalPageScaleFactor(float page_scale_factor); + + // Requests that we force send RenderFrameMetadata with the next frame. + void RequestForceSendMetadata() { force_send_metadata_request_ = true; } + + // Returns the state of |force_send_metadata_request_| and resets the + // variable to false. + bool TakeForceSendMetadataRequest(); + // Used externally by blink for setting the PropertyTrees when // UseLayerLists() is true, which also implies that Slimming Paint // v2 is enabled. @@ -470,8 +500,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void SetElasticOverscrollFromImplSide(gfx::Vector2dF elastic_overscroll); gfx::Vector2dF elastic_overscroll() const { return elastic_overscroll_; } - // Ensures a HUD layer exists if it is needed, and updates the layer bounds. - // If a HUD layer exists but is no longer needed, it is destroyed. + // Ensures a HUD layer exists if it is needed, and updates the HUD bounds and + // position. If a HUD layer exists but is no longer needed, it is destroyed. void UpdateHudLayer(bool show_hud_info); HeadsUpDisplayLayer* hud_layer() const { return hud_layer_.get(); } @@ -487,6 +517,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void PushPropertyTreesTo(LayerTreeImpl* tree_impl); void PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl); + // TODO(flackr): This list should be on the property trees and pushed + // as part of PushPropertyTreesTo. + void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl); void PushSurfaceRangesTo(LayerTreeImpl* tree_impl); void PushLayerTreeHostPropertiesTo(LayerTreeHostImpl* host_impl); @@ -497,6 +530,17 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { ElementListType list_type, Layer* layer); void UnregisterElement(ElementId element_id, ElementListType list_type); + + // Registers the new active element ids, updating |registered_element_ids_|, + // and unregisters any element ids that were previously registered. This is + // similar to |RegisterElement| and |UnregisterElement| but for layer lists + // where we do not have a unique element id to layer mapping. + using ElementIdSet = std::unordered_set<ElementId, ElementIdHash>; + void SetActiveRegisteredElementIds(const ElementIdSet&); + const ElementIdSet& elements_in_property_trees() { + return elements_in_property_trees_; + } + void SetElementIdsForTesting(); void BuildPropertyTreesForTesting(); @@ -514,7 +558,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void BeginMainFrameNotExpectedSoon(); void BeginMainFrameNotExpectedUntil(base::TimeTicks time); void AnimateLayers(base::TimeTicks monotonic_frame_begin_time); - void RequestMainFrameUpdate(); + void RequestMainFrameUpdate(bool record_main_frame_metrics); void FinishCommitOnImplThread(LayerTreeHostImpl* host_impl); void WillCommit(); void CommitComplete(); @@ -641,20 +685,20 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { private: friend class LayerTreeHostSerializationTest; - friend class ScopedDeferCommits; + friend class ScopedDeferMainFrameUpdate; // This is the number of consecutive frames in which we want the content to be // free of slow-paths before toggling the flag. enum { kNumFramesToConsiderBeforeRemovingSlowPathFlag = 60 }; - void ApplyViewportDeltas(const ScrollAndScaleSet& info); + void ApplyViewportChanges(const ScrollAndScaleSet& info); void RecordWheelAndTouchScrollingCount(const ScrollAndScaleSet& info); void ApplyPageScaleDeltaFromImplSide(float page_scale_delta); void InitializeProxy(std::unique_ptr<Proxy> proxy); bool DoUpdateLayers(Layer* root_layer); - void UpdateDeferCommitsInternal(); + void UpdateDeferMainFrameUpdateInternal(); const CompositorMode compositor_mode_; @@ -706,6 +750,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { scoped_refptr<Layer> root_layer_; ViewportLayers viewport_layers_; + // For CompositeAfterPaint. + ViewportPropertyIds viewport_property_ids_; float top_controls_height_ = 0.f; float top_controls_shown_ratio_ = 0.f; @@ -720,17 +766,18 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { float page_scale_factor_ = 1.f; float min_page_scale_factor_ = 1.f; float max_page_scale_factor_ = 1.f; + float external_page_scale_factor_ = 1.f; int raster_color_space_id_ = -1; gfx::ColorSpace raster_color_space_; bool clear_caches_on_next_commit_ = false; uint32_t content_source_id_; - viz::LocalSurfaceId local_surface_id_from_parent_; + viz::LocalSurfaceIdAllocation local_surface_id_allocation_from_parent_; // Used to detect surface invariant violations. bool has_pushed_local_surface_id_from_parent_ = false; bool new_local_surface_id_request_ = false; - uint32_t defer_commits_count_ = 0; + uint32_t defer_main_frame_update_count_ = 0; SkColor background_color_ = SK_ColorWHITE; @@ -746,6 +793,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation_; + // Whether we have a pending request to force send RenderFrameMetadata with + // the next frame. + bool force_send_metadata_request_ = false; + PropertyTrees property_trees_; bool needs_full_tree_sync_ = true; @@ -768,6 +819,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { std::unordered_map<ElementId, Layer*, ElementIdHash> element_layers_map_; + // The set of registered element ids when using layer list mode. In non-layer- + // list mode, |element_layers_map_| is used. + ElementIdSet elements_in_property_trees_; + bool in_paint_layer_contents_ = false; // This is true if atleast one layer in the layer tree has a copy request. We @@ -786,8 +841,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // added here. std::vector<PresentationTimeCallback> pending_presentation_time_callbacks_; - // Used to vend weak pointers to LayerTreeHost to ScopedDeferCommits objects. - base::WeakPtrFactory<LayerTreeHost> defer_commits_weak_ptr_factory_; + // Used to vend weak pointers to LayerTreeHost to ScopedDeferMainFrameUpdate + // objects. + base::WeakPtrFactory<LayerTreeHost> defer_main_frame_update_weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(LayerTreeHost); }; diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index 97150433e01..2973940a711 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -9,11 +9,12 @@ #include "base/memory/ref_counted.h" #include "base/time/time.h" +#include "cc/input/browser_controls_state.h" +#include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/geometry/vector2d_f.h" namespace gfx { struct PresentationFeedback; -class Vector2dF; } namespace viz { @@ -24,7 +25,7 @@ namespace cc { struct ApplyViewportChangesArgs { // Scroll offset delta of the inner (visual) viewport. - gfx::Vector2dF inner_delta; + gfx::ScrollOffset inner_delta; // Elastic overscroll effect offset delta. This is used only on Mac. a.k.a // "rubber-banding" overscroll. @@ -37,6 +38,14 @@ struct ApplyViewportChangesArgs { // How much the browser controls have been shown or hidden. The ratio runs // between 0 (hidden) and 1 (full-shown). This is additive. float browser_controls_delta; + + // Whether the browser controls have been locked to fully hidden or shown or + // whether they can be freely moved. + BrowserControlsState browser_controls_constraint; + + // Set to true when a scroll gesture being handled on the compositor has + // ended. + bool scroll_gesture_did_end; }; // A LayerTreeHost is bound to a LayerTreeHostClient. The main rendering @@ -80,8 +89,11 @@ class LayerTreeHostClient { // (Blink's notions of) style, layout, paint invalidation and compositing // state. (The "compositing state" will result in a mutated layer tree on the // LayerTreeHost via additional interface indirections which lead back to - // mutations on the LayerTreeHost.) - virtual void UpdateLayerTreeHost() = 0; + // mutations on the LayerTreeHost.) The |record_main_frame_metrics| flag + // determines whether Blink will compute metrics related to main frame update + // time. If true, the caller must ensure that RecordEndOfFrameMetrics is + // called when this method returns and the total main frame time is known. + virtual void UpdateLayerTreeHost(bool record_main_frame_metrics) = 0; // Notifies the client of viewport-related changes that occured in the // LayerTreeHost since the last commit. This typically includes things diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc index f3631c4cb05..16bee1698d4 100644 --- a/chromium/cc/trees/layer_tree_host_common.cc +++ b/chromium/cc/trees/layer_tree_host_common.cc @@ -178,8 +178,11 @@ bool LayerTreeHostCommon::ScrollbarsUpdateInfo::operator==( ScrollAndScaleSet::ScrollAndScaleSet() : page_scale_delta(1.f), top_controls_delta(0.f), + browser_controls_constraint(BrowserControlsState::kBoth), + browser_controls_constraint_changed(false), has_scrolled_by_wheel(false), - has_scrolled_by_touch(false) {} + has_scrolled_by_touch(false), + scroll_gesture_did_end(false) {} ScrollAndScaleSet::~ScrollAndScaleSet() = default; @@ -200,12 +203,6 @@ static inline void ClearMaskLayersContributeToDrawnRenderSurface( mask_layer->set_contributes_to_drawn_render_surface(false); } -static bool CdpPerfTracingEnabled() { - bool tracing_enabled; - TRACE_EVENT_CATEGORY_GROUP_ENABLED("cdp.perf", &tracing_enabled); - return tracing_enabled; -} - static float TranslationFromActiveTreeLayerScreenSpaceTransform( LayerImpl* pending_tree_layer) { LayerTreeImpl* layer_tree_impl = pending_tree_layer->layer_tree_impl(); @@ -496,21 +493,12 @@ void CalculateDrawPropertiesInternal( PropertyTreeOption property_tree_option) { inputs->render_surface_list->clear(); - const bool should_measure_property_tree_performance = - property_tree_option == BUILD_PROPERTY_TREES; - LayerImplList visible_layer_list; switch (property_tree_option) { case BUILD_PROPERTY_TREES: { // The translation from layer to property trees is an intermediate // state. We will eventually get these data passed directly to the // compositor. - if (should_measure_property_tree_performance) { - TRACE_EVENT_BEGIN0( - TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees"); - } - PropertyTreeBuilder::BuildPropertyTrees( inputs->root_layer, inputs->page_scale_layer, inputs->inner_viewport_scroll_layer, @@ -530,18 +518,9 @@ void CalculateDrawPropertiesInternal( // updates when they are built on compositor thread. inputs->property_trees->transform_tree .set_source_to_parent_updates_allowed(false); - if (should_measure_property_tree_performance) { - TRACE_EVENT_END0( - TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees"); - } - break; } case DONT_BUILD_PROPERTY_TREES: { - TRACE_EVENT0( - TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::ComputeJustVisibleRectsWithPropertyTrees"); // Since page scale and elastic overscroll are SyncedProperties, changes // on the active tree immediately affect the pending tree, so instead of // trying to update property trees whenever these values change, we @@ -603,11 +582,6 @@ void CalculateDrawPropertiesInternal( } } - if (should_measure_property_tree_performance) { - TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::CalculateDrawProperties"); - } - { TRACE_EVENT0("cc", "draw_property_utils::FindLayersThatNeedUpdates"); draw_property_utils::FindLayersThatNeedUpdates( @@ -630,11 +604,6 @@ void CalculateDrawPropertiesInternal( inputs->render_surface_list, inputs->max_texture_size); } - if (should_measure_property_tree_performance) { - TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), - "LayerTreeHostCommon::CalculateDrawProperties"); - } - // A root layer render_surface should always exist after // CalculateDrawProperties. DCHECK(inputs->property_trees->effect_tree.GetRenderSurface( @@ -663,48 +632,6 @@ void LayerTreeHostCommon::CalculateDrawPropertiesForTesting( void LayerTreeHostCommon::CalculateDrawProperties( CalcDrawPropsImplInputs* inputs) { CalculateDrawPropertiesInternal(inputs, DONT_BUILD_PROPERTY_TREES); - - if (CdpPerfTracingEnabled()) { - LayerTreeImpl* layer_tree_impl = inputs->root_layer->layer_tree_impl(); - if (layer_tree_impl->IsPendingTree() && - layer_tree_impl->is_first_frame_after_commit()) { - LayerImpl* active_tree_root = - layer_tree_impl->FindActiveTreeLayerById(inputs->root_layer->id()); - float jitter = 0.f; - if (active_tree_root) { - int last_scrolled_node_index = - active_tree_root->layer_tree_impl()->LastScrolledScrollNodeIndex(); - if (last_scrolled_node_index != ScrollTree::kInvalidNodeId) { - std::unordered_set<int> jitter_nodes; - for (auto* layer : *layer_tree_impl) { - // Layers that have the same scroll tree index jitter together. So, - // it is enough to calculate jitter on one of these layers. So, - // after we find a jittering layer, we need not consider other - // layers with the same scroll tree index. - int scroll_tree_index = layer->scroll_tree_index(); - if (last_scrolled_node_index <= scroll_tree_index && - jitter_nodes.find(scroll_tree_index) == jitter_nodes.end()) { - float layer_jitter = CalculateLayerJitter(layer); - if (layer_jitter > 0.f) { - jitter_nodes.insert(layer->scroll_tree_index()); - jitter += layer_jitter; - } - } - } - } - } - TRACE_EVENT_ASYNC_BEGIN1( - "cdp.perf", "jitter", - inputs->root_layer->layer_tree_impl()->source_frame_number(), "value", - jitter); - inputs->root_layer->layer_tree_impl()->set_is_first_frame_after_commit( - false); - TRACE_EVENT_ASYNC_END1( - "cdp.perf", "jitter", - inputs->root_layer->layer_tree_impl()->source_frame_number(), "value", - jitter); - } - } } void LayerTreeHostCommon::CalculateDrawPropertiesForTesting( diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h index 6116eaf5300..42de6d2ab68 100644 --- a/chromium/cc/trees/layer_tree_host_common.h +++ b/chromium/cc/trees/layer_tree_host_common.h @@ -14,6 +14,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "cc/cc_export.h" +#include "cc/input/browser_controls_state.h" #include "cc/layers/layer.h" #include "cc/layers/layer_collections.h" #include "cc/layers/layer_impl.h" @@ -134,9 +135,7 @@ class CC_EXPORT LayerTreeHostCommon { struct CC_EXPORT ScrollUpdateInfo { ElementId element_id; - // TODO(miletus): Use ScrollOffset once LayerTreeHost/Blink fully supports - // fractional scroll offset. - gfx::Vector2d scroll_delta; + gfx::ScrollOffset scroll_delta; bool operator==(const ScrollUpdateInfo& other) const; }; @@ -173,9 +172,15 @@ struct CC_EXPORT ScrollAndScaleSet { float top_controls_delta; std::vector<LayerTreeHostCommon::ScrollbarsUpdateInfo> scrollbars; std::vector<std::unique_ptr<SwapPromise>> swap_promises; + BrowserControlsState browser_controls_constraint; + bool browser_controls_constraint_changed; bool has_scrolled_by_wheel; bool has_scrolled_by_touch; + // Set to true when a scroll gesture being handled on the compositor has + // ended. + bool scroll_gesture_did_end; + private: DISALLOW_COPY_AND_ASSIGN(ScrollAndScaleSet); }; diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc index 991303a6456..561cdd1ade5 100644 --- a/chromium/cc/trees/layer_tree_host_common_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc @@ -50,7 +50,7 @@ class LayerTreeHostCommonPerfTest : public LayerTreeTest { void SetupTree() override { gfx::Size viewport = gfx::Size(720, 1038); layer_tree_host()->SetViewportSizeAndScale(viewport, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); scoped_refptr<Layer> root = ParseTreeFromJson(json_, &content_layer_client_); ASSERT_TRUE(root.get()); diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc index 57bed051c21..17a78468e72 100644 --- a/chromium/cc/trees/layer_tree_host_common_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc @@ -1409,7 +1409,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) { } TEST_F(LayerTreeHostCommonTest, - RenderSurfaceListForTransparentChildWithBackgroundFilter) { + RenderSurfaceListForTransparentChildWithBackdropFilter) { LayerImpl* root = root_layer_for_testing(); LayerImpl* render_surface1 = AddChild<LayerImpl>(root); LayerImpl* child = AddChild<LayerImpl>(render_surface1); @@ -1421,7 +1421,7 @@ TEST_F(LayerTreeHostCommonTest, render_surface1->SetDrawsContent(true); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(1.5f)); - render_surface1->test_properties()->background_filters = filters; + render_surface1->test_properties()->backdrop_filters = filters; child->SetBounds(gfx::Size(10, 10)); child->SetDrawsContent(true); root->layer_tree_impl()->SetElementIdsForTesting(); @@ -1434,7 +1434,7 @@ TEST_F(LayerTreeHostCommonTest, LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs); EXPECT_EQ(2U, render_surface_list.size()); } - // The layer is fully transparent, but has a background filter, so it + // The layer is fully transparent, but has a backdrop filter, so it // shouldn't be skipped and should be drawn. ASSERT_TRUE(GetRenderSurface(root)); EXPECT_EQ(1, GetRenderSurface(root)->num_contributors()); diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index 9b1e5d7484e..dcfc217ced6 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -25,8 +25,8 @@ #include "base/numerics/safe_conversions.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" -#include "base/sys_info.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/system/sys_info.h" +#include "base/trace_event/traced_value.h" #include "build/build_config.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" @@ -40,6 +40,7 @@ #include "cc/input/scroll_state.h" #include "cc/input/scrollbar_animation_controller.h" #include "cc/input/scroller_size_metrics.h" +#include "cc/input/snap_selection_strategy.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/effect_tree_layer_list_iterator.h" #include "cc/layers/heads_up_display_layer_impl.h" @@ -330,7 +331,8 @@ LayerTreeHostImpl::LayerTreeHostImpl( frame_metrics_(LTHI_FrameMetricsSettings(settings_)), skipped_frame_tracker_(&frame_metrics_), is_animating_for_snap_(false), - paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()) { + paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()), + scroll_gesture_did_end_(false) { DCHECK(mutator_host_); mutator_host_->SetMutatorHostClient(this); @@ -455,7 +457,7 @@ void LayerTreeHostImpl::CommitComplete() { void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() { // LayerTreeHost may have changed the GPU rasterization flags state, which // may require an update of the tree resources. - UpdateTreeResourcesForGpuRasterizationIfNeeded(); + UpdateTreeResourcesIfNeeded(); sync_tree()->set_needs_update_draw_properties(); // We need an update immediately post-commit to have the opportunity to create @@ -478,16 +480,15 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() { // Defer invalidating images until UpdateDrawProperties is performed since // that updates whether an image should be animated based on its visibility // and the updated data for the image from the main frame. - PaintImageIdFlatSet images_to_invalidate = - tile_manager_.TakeImagesToInvalidateOnSyncTree(); - if (ukm_manager_) - ukm_manager_->AddCheckerboardedImages(images_to_invalidate.size()); + 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().frame_time); - images_to_invalidate.insert(animated_images.begin(), animated_images.end()); - sync_tree()->InvalidateRegionForImages(images_to_invalidate); + const auto& animated_images = image_animation_controller_.AnimateForSyncTree( + CurrentBeginFrameArgs().frame_time); + images_to_invalidate.insert(animated_images.begin(), animated_images.end()); + sync_tree()->InvalidateRegionForImages(images_to_invalidate); // Note that it is important to push the state for checkerboarded and animated // images prior to PrepareTiles here when committing to the active tree. This @@ -950,8 +951,8 @@ bool LayerTreeHostImpl::HasDamage() const { // If we have a new LocalSurfaceId, we must always submit a CompositorFrame // because the parent is blocking on us. - if (last_draw_local_surface_id_ != - child_local_surface_id_allocator_.GetCurrentLocalSurfaceId()) { + if (last_draw_local_surface_id_allocation_ != + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()) { return true; } @@ -1249,12 +1250,13 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) { UMA_HISTOGRAM_PERCENTAGE( "Compositing.RenderPass.AppendQuadData.RCMaskLayerPercent", rc_mask_layer_percent); + UMA_HISTOGRAM_PERCENTAGE( + "Compositing.RenderPass.AppendQuadData.RCMaskAreaPercent", + rc_area_percent); + UMA_HISTOGRAM_COUNTS_10M( + "Compositing.RenderPass.AppendQuadData.RCMaskArea", + visible_rounded_corner_mask_layer_area); } - UMA_HISTOGRAM_PERCENTAGE( - "Compositing.RenderPass.AppendQuadData.RCMaskAreaPercent", - rc_area_percent); - UMA_HISTOGRAM_COUNTS_10M("Compositing.RenderPass.AppendQuadData.RCMaskArea", - visible_rounded_corner_mask_layer_area); } TRACE_EVENT_END2("cc,benchmark", "LayerTreeHostImpl::CalculateRenderPasses", @@ -1386,11 +1388,6 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) { } DrawResult draw_result = CalculateRenderPasses(frame); - if (client_name) { - UMA_HISTOGRAM_ENUMERATION( - base::StringPrintf("Compositing.%s.DrawResult", client_name), - draw_result); - } if (draw_result != DRAW_SUCCESS) { DCHECK(!resourceless_software_draw_); return draw_result; @@ -1441,7 +1438,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) { } if (pass->quad_list.empty() && pass->copy_requests.empty() && - pass->filters.IsEmpty() && pass->background_filters.IsEmpty()) { + pass->filters.IsEmpty() && pass->backdrop_filters.IsEmpty()) { // Remove the pass and decrement |i| to counter the for loop's increment, // so we don't skip the next pass in the loop. frame->render_passes.erase(frame->render_passes.begin() + i); @@ -1811,8 +1808,6 @@ LayerTreeHostImpl::FrameTokenInfo::~FrameTokenInfo() = default; void LayerTreeHostImpl::DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) { - TRACE_EVENT_MARK_WITH_TIMESTAMP0("cc,benchmark", "FramePresented", - feedback.timestamp); std::vector<LayerTreeHost::PresentationTimeCallback> all_callbacks; while (!frame_token_infos_.empty()) { auto info = frame_token_infos_.begin(); @@ -1833,6 +1828,10 @@ void LayerTreeHostImpl::DidPresentCompositorFrame( frame_token, std::move(all_callbacks), feedback); } +void LayerTreeHostImpl::DidNotNeedBeginFrame() { + skipped_frame_tracker_.WillNotProduceFrame(); +} + void LayerTreeHostImpl::ReclaimResources( const std::vector<viz::ReturnedResource>& resources) { resource_provider_.ReceiveReturnsFromParent(resources); @@ -1959,6 +1958,10 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() { metadata.top_controls_shown_ratio = browser_controls_offset_manager_->TopControlsShownRatio(); + metadata.local_surface_id_allocation_time = + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() + .allocation_time(); + #if defined(OS_ANDROID) metadata.max_page_scale_factor = active_tree_->max_page_scale_factor(); metadata.root_layer_size = active_tree_->ScrollableSize(); @@ -2007,6 +2010,8 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata( metadata.viewport_size_in_pixels = active_tree_->GetDeviceViewport().size(); metadata.page_scale_factor = active_tree_->current_page_scale_factor(); + metadata.external_page_scale_factor = + active_tree_->external_page_scale_factor(); metadata.top_controls_height = browser_controls_offset_manager_->TopControlsHeight(); @@ -2056,12 +2061,12 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata( metadata.has_transparent_background); #endif - viz::LocalSurfaceId local_surface_id = - child_local_surface_id_allocator_.GetCurrentLocalSurfaceId(); - if (local_surface_id.is_valid()) { + if (child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() + .IsValid()) { if (allocate_new_local_surface_id) - local_surface_id = child_local_surface_id_allocator_.GenerateId(); - metadata.local_surface_id = local_surface_id; + child_local_surface_id_allocator_.GenerateId(); + metadata.local_surface_id_allocation = + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); } return metadata; @@ -2082,7 +2087,8 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) { } auto compositor_frame = GenerateCompositorFrame(frame); - layer_tree_frame_sink_->SubmitCompositorFrame(std::move(compositor_frame)); + layer_tree_frame_sink_->SubmitCompositorFrame( + std::move(compositor_frame), debug_state_.show_hit_test_borders); // Clears the list of swap promises after calling DidSwap on each of them to // signal that the swap is over. @@ -2139,7 +2145,7 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( { TRACE_EVENT0("cc", "DrawLayers.FrameViewerTracing"); TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - frame_viewer_instrumentation::kCategoryLayerTree, + frame_viewer_instrumentation::CategoryLayerTree(), "cc::LayerTreeHostImpl", id_, AsValueWithFrame(frame)); } @@ -2173,7 +2179,8 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( if (render_frame_metadata_observer_) { last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame); render_frame_metadata_observer_->OnRenderFrameSubmission( - *last_draw_render_frame_metadata_, &metadata); + *last_draw_render_frame_metadata_, &metadata, + active_tree()->TakeForceSendMetadataRequest()); } metadata.latency_info.emplace_back(ui::SourceEventType::FRAME); @@ -2222,12 +2229,13 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( // LocalSurfaceId might slip through, but single-thread-without-scheduler // mode is only used in tests so it doesn't matter. CHECK(!settings_.single_thread_proxy_scheduler || - active_tree()->local_surface_id_from_parent().is_valid()); + active_tree()->local_surface_id_allocation_from_parent().IsValid()); layer_tree_frame_sink_->SetLocalSurfaceId( - child_local_surface_id_allocator_.GetCurrentLocalSurfaceId()); + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() + .local_surface_id()); } - last_draw_local_surface_id_ = - child_local_surface_id_allocator_.GetCurrentLocalSurfaceId(); + last_draw_local_surface_id_allocation_ = + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); if (const char* client_name = GetClientNameForMetrics()) { size_t total_quad_count = 0; for (const auto& pass : compositor_frame.render_pass_list) @@ -2409,8 +2417,15 @@ bool LayerTreeHostImpl::UpdateGpuRasterizationStatus() { return true; } -void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() { - if (!UpdateGpuRasterizationStatus()) +void LayerTreeHostImpl::UpdateTreeResourcesIfNeeded() { + // For simplicity, clobber all resources when the color space changes. + // This is mostly to clear the image decode caches, which don't handle + // multiple color space at once. + int color_space_id = GetRasterColorSpace().color_space_id; + bool color_space_changed = last_color_space_id_ != color_space_id; + last_color_space_id_ = color_space_id; + + if (!UpdateGpuRasterizationStatus() && !color_space_changed) return; // Clean up and replace existing tile manager with another one that uses @@ -2597,11 +2612,15 @@ static uint32_t GetFlagsForSurfaceLayer(const SurfaceLayerImpl* layer) { static void PopulateHitTestRegion(viz::HitTestRegion* hit_test_region, const LayerImpl* layer, uint32_t flags, + uint32_t async_hit_test_reasons, const gfx::Rect& rect, const viz::SurfaceId& surface_id, float device_scale_factor) { hit_test_region->frame_sink_id = surface_id.frame_sink_id(); hit_test_region->flags = flags; + hit_test_region->async_hit_test_reasons = async_hit_test_reasons; + DCHECK_EQ(!!async_hit_test_reasons, + !!(flags & viz::HitTestRegionFlags::kHitTestAsk)); hit_test_region->rect = rect; // The transform of hit test region maps a point from parent hit test region @@ -2662,12 +2681,13 @@ base::Optional<viz::HitTestRegionList> LayerTreeHostImpl::BuildHitTestData() { gfx::Rect layer_screen_space_rect = MathUtil::MapEnclosingClippedRect( surface_layer->ScreenSpaceTransform(), gfx::Rect(surface_layer->bounds())); - if (overlapping_region.Contains(layer_screen_space_rect)) - continue; - auto flag = GetFlagsForSurfaceLayer(surface_layer); - if (overlapping_region.Intersects(layer_screen_space_rect)) + uint32_t async_hit_test_reasons = + viz::AsyncHitTestReasons::kNotAsyncHitTest; + if (overlapping_region.Intersects(layer_screen_space_rect)) { flag |= viz::HitTestRegionFlags::kHitTestAsk; + async_hit_test_reasons |= viz::AsyncHitTestReasons::kOverlappedRegion; + } if (surface_layer->is_clipped()) { bool layer_hit_test_region_is_rectangle = active_tree() @@ -2678,13 +2698,16 @@ base::Optional<viz::HitTestRegionList> LayerTreeHostImpl::BuildHitTestData() { content_rect = gfx::ScaleToEnclosingRect(surface_layer->visible_layer_rect(), device_scale_factor, device_scale_factor); - if (!layer_hit_test_region_is_rectangle) + if (!layer_hit_test_region_is_rectangle) { flag |= viz::HitTestRegionFlags::kHitTestAsk; + async_hit_test_reasons |= viz::AsyncHitTestReasons::kIrregularClip; + } } const auto& surface_id = surface_layer->range().end(); hit_test_region_list->regions.emplace_back(); PopulateHitTestRegion(&hit_test_region_list->regions.back(), layer, flag, - content_rect, surface_id, device_scale_factor); + async_hit_test_reasons, content_rect, surface_id, + device_scale_factor); continue; } // TODO(sunxd): Submit all overlapping layer bounds as hit test regions. @@ -2711,6 +2734,10 @@ bool LayerTreeHostImpl::HaveRootScrollNode() const { return InnerViewportScrollNode(); } +void LayerTreeHostImpl::SetNeedsCommit() { + client_->SetNeedsCommitOnImplThread(); +} + LayerImpl* LayerTreeHostImpl::InnerViewportContainerLayer() const { return active_tree_->InnerViewportContainerLayer(); } @@ -2904,9 +2931,9 @@ void LayerTreeHostImpl::ActivateSyncTree() { UpdateRootLayerStateForSynchronousInputHandler(); // Update the child's LocalSurfaceId. - if (active_tree()->local_surface_id_from_parent().is_valid()) { + if (active_tree()->local_surface_id_allocation_from_parent().IsValid()) { child_local_surface_id_allocator_.UpdateFromParent( - active_tree()->local_surface_id_from_parent()); + active_tree()->local_surface_id_allocation_from_parent()); if (active_tree()->TakeNewLocalSurfaceIdRequest()) child_local_surface_id_allocator_.GenerateId(); } @@ -2914,22 +2941,14 @@ void LayerTreeHostImpl::ActivateSyncTree() { // Dump property trees and layers if run with: // --vmodule=layer_tree_host_impl=3 if (VLOG_IS_ON(3)) { - VLOG(3) << "After activating sync tree, the active tree:"; - // Because the property tree and layer list output can be verbose, the VLOG - // output is split by line to avoid line buffer limits on android. - VLOG(3) << "property trees:"; std::string property_trees; base::JSONWriter::WriteWithOptions( *active_tree_->property_trees()->AsTracedValue()->ToBaseValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &property_trees); - std::stringstream property_trees_stream(property_trees); - for (std::string line; std::getline(property_trees_stream, line);) - VLOG(3) << line; - - VLOG(3) << "layers:"; - std::stringstream layers_stream(LayerListAsJson()); - for (std::string line; std::getline(layers_stream, line);) - VLOG(3) << line; + VLOG(3) << "After activating sync tree, the active tree:" + << "\nproperty_trees:\n" + << property_trees << "\nlayers:\n" + << LayerListAsJson(); } } @@ -2989,6 +3008,12 @@ void LayerTreeHostImpl::SetVisible(bool visible) { SetFullViewportDamage(); SetNeedsRedraw(); } + // If surface synchronization is off, force allocating a new LocalSurfaceId + // because the previous LocalSurfaceId might have been evicted while we were + // invisible. When surface synchronization is on, the embedder will pass us + // a new LocalSurfaceID. + if (layer_tree_frame_sink_ && !settings_.enable_surface_synchronization) + layer_tree_frame_sink_->ForceAllocateNewId(); } else { EvictAllUIResources(); // Call PrepareTiles to evict tiles when we become invisible. @@ -3008,7 +3033,8 @@ void LayerTreeHostImpl::SetNeedsOneBeginImplFrame() { void LayerTreeHostImpl::SetNeedsRedraw() { NotifySwapPromiseMonitorsOfSetNeedsRedraw(); client_->SetNeedsRedrawOnImplThread(); - skipped_frame_tracker_.WillProduceFrame(); + if (CurrentlyScrollingNode()) + skipped_frame_tracker_.WillProduceFrame(); } ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const { @@ -3067,13 +3093,15 @@ void LayerTreeHostImpl::CreateTileManagerResources() { viz::ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true, tile_format), settings_.decoded_image_working_set_budget_bytes, max_texture_size_, - paint_image_generator_client_id_); + paint_image_generator_client_id_, + GetRasterColorSpace().color_space.ToSkColorSpace()); } else { bool gpu_compositing = !!layer_tree_frame_sink_->context_provider(); image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>( viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format), settings_.decoded_image_working_set_budget_bytes, - paint_image_generator_client_id_); + paint_image_generator_client_id_, + GetRasterColorSpace().color_space.ToSkColorSpace()); } // Pass the single-threaded synchronous task graph runner to the worker pool @@ -3173,9 +3201,8 @@ void LayerTreeHostImpl::QueueImageDecode(int request_id, // Optimistically specify the current raster color space, since we assume that // it won't change. tile_manager_.decoded_image_tracker().QueueImageDecode( - image, GetRasterColorSpace().color_space, - base::Bind(&LayerTreeHostImpl::ImageDecodeFinished, - base::Unretained(this), request_id)); + image, base::Bind(&LayerTreeHostImpl::ImageDecodeFinished, + base::Unretained(this), request_id)); tile_manager_.checker_image_tracker().DisallowCheckeringForImage(image); } @@ -3357,6 +3384,18 @@ bool LayerTreeHostImpl::InitializeFrameSink( // TODO(crbug.com/469175): Replace with RequiresHighResToDraw. SetRequiresHighResToDraw(); + // Always allocate a new viz::LocalSurfaceId when we get a new + // LayerTreeFrameSink to ensure that we do not reuse the same surface after + // it might have been garbage collected. + if (settings_.enable_surface_synchronization) { + const viz::LocalSurfaceIdAllocation& local_surface_id_allocation = + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); + if (local_surface_id_allocation.IsValid()) + child_local_surface_id_allocator_.GenerateId(); + } else { + layer_tree_frame_sink_->ForceAllocateNewId(); + } + return true; } @@ -4493,12 +4532,13 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() { const SnapContainerData& data = scroll_node->snap_container_data.value(); gfx::ScrollOffset current_position = GetVisualScrollOffset(*scroll_node); + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndPosition( + current_position, did_scroll_x_for_scroll_gesture_, + did_scroll_y_for_scroll_gesture_); gfx::ScrollOffset snap_position; - if (!data.FindSnapPosition(current_position, did_scroll_x_for_scroll_gesture_, - did_scroll_y_for_scroll_gesture_, - &snap_position)) { + if (!data.FindSnapPosition(*strategy, &snap_position)) return false; - } gfx::Vector2dF delta = ScrollOffsetToVector2dF(snap_position - current_position); @@ -4541,8 +4581,8 @@ gfx::ScrollOffset LayerTreeHostImpl::GetVisualScrollOffset( bool LayerTreeHostImpl::GetSnapFlingInfo( const gfx::Vector2dF& natural_displacement_in_viewport, - gfx::Vector2dF* out_initial_offset, - gfx::Vector2dF* out_target_offset) const { + gfx::Vector2dF* out_initial_position, + gfx::Vector2dF* out_target_position) const { const ScrollNode* scroll_node = CurrentlyScrollingNode(); if (!scroll_node || !scroll_node->snap_container_data.has_value()) return false; @@ -4552,24 +4592,19 @@ bool LayerTreeHostImpl::GetSnapFlingInfo( gfx::Vector2dF natural_displacement_in_content = gfx::ScaleVector2d(natural_displacement_in_viewport, 1.f / scale_factor); - *out_initial_offset = - ScrollOffsetToVector2dF(GetVisualScrollOffset(*scroll_node)); - - bool did_scroll_x = did_scroll_x_for_scroll_gesture_ || - natural_displacement_in_content.x() != 0; - bool did_scroll_y = did_scroll_y_for_scroll_gesture_ || - natural_displacement_in_content.y() != 0; + gfx::ScrollOffset current_offset = GetVisualScrollOffset(*scroll_node); + *out_initial_position = ScrollOffsetToVector2dF(current_offset); gfx::ScrollOffset snap_offset; - if (!data.FindSnapPosition(gfx::ScrollOffset(*out_initial_offset + - natural_displacement_in_content), - did_scroll_x, did_scroll_y, &snap_offset)) { + std::unique_ptr<SnapSelectionStrategy> strategy = + SnapSelectionStrategy::CreateForEndAndDirection( + current_offset, gfx::ScrollOffset(natural_displacement_in_content)); + if (!data.FindSnapPosition(*strategy, &snap_offset)) return false; - } - *out_target_offset = ScrollOffsetToVector2dF(snap_offset); - out_target_offset->Scale(scale_factor); - out_initial_offset->Scale(scale_factor); + *out_target_position = ScrollOffsetToVector2dF(snap_offset); + out_target_position->Scale(scale_factor); + out_initial_position->Scale(scale_factor); return true; } @@ -4594,6 +4629,8 @@ void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) { } void LayerTreeHostImpl::ScrollEnd(ScrollState* scroll_state, bool should_snap) { + scroll_gesture_did_end_ = true; + if (should_snap && SnapAtScrollEnd()) return; @@ -4739,7 +4776,8 @@ void LayerTreeHostImpl::CollectScrollDeltas( : ElementId(); active_tree_->property_trees()->scroll_tree.CollectScrollDeltas( - scroll_info, inner_viewport_scroll_element_id); + scroll_info, inner_viewport_scroll_element_id, + active_tree_->settings().commit_fractional_scroll_deltas); } void LayerTreeHostImpl::CollectScrollbarUpdates( @@ -4772,8 +4810,16 @@ std::unique_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() { // Record and reset scroll source flags. scroll_info->has_scrolled_by_wheel = has_scrolled_by_wheel_; scroll_info->has_scrolled_by_touch = has_scrolled_by_touch_; + scroll_info->scroll_gesture_did_end = scroll_gesture_did_end_; has_scrolled_by_wheel_ = has_scrolled_by_touch_ = false; + if (browser_controls_manager()) { + scroll_info->browser_controls_constraint = + browser_controls_manager()->PullConstraintForMainThread( + &scroll_info->browser_controls_constraint_changed); + } + + scroll_gesture_did_end_ = false; return scroll_info; } diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index a215f1cb908..b932defe22e 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -67,12 +67,12 @@ class CompositorFrameMetadata; namespace cc { class BrowserControlsOffsetManager; -class LayerTreeFrameSink; class DebugRectHistory; class EvictionTilePriorityQueue; class FrameRateCounter; class ImageAnimationController; class LayerImpl; +class LayerTreeFrameSink; class LayerTreeImpl; class MemoryHistory; class MutatorEvents; @@ -91,7 +91,6 @@ class SwapPromiseMonitor; class SynchronousTaskGraphRunner; class TaskGraphRunner; class UIResourceBitmap; -struct ScrollAndScaleSet; class Viewport; using BeginFrameCallbackList = std::vector<base::Closure>; @@ -295,6 +294,7 @@ class CC_EXPORT LayerTreeHostImpl float CurrentBrowserControlsShownRatio() const override; void DidChangeBrowserControlsPosition() override; bool HaveRootScrollNode() const override; + void SetNeedsCommit() override; void UpdateViewportContainerSizes(); @@ -306,6 +306,7 @@ class CC_EXPORT LayerTreeHostImpl return viewport_damage_rect_; } + virtual void WillSendBeginMainFrame() {} virtual void DidSendBeginMainFrame() {} virtual void BeginMainFrameAborted( CommitEarlyOutReason reason, @@ -442,6 +443,7 @@ class CC_EXPORT LayerTreeHostImpl void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override; + void DidNotNeedBeginFrame() override; void ReclaimResources( const std::vector<viz::ReturnedResource>& resources) override; void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override; @@ -542,7 +544,6 @@ class CC_EXPORT LayerTreeHostImpl return is_animating_for_snap_; } - void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); } void SetNeedsOneBeginImplFrame(); void SetNeedsRedraw(); @@ -615,8 +616,8 @@ class CC_EXPORT LayerTreeHostImpl gfx::ScrollOffset GetVisualScrollOffset(const ScrollNode& scroll_node) const; bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement_in_viewport, - gfx::Vector2dF* out_initial_offset, - gfx::Vector2dF* out_target_offset) const override; + gfx::Vector2dF* out_initial_position, + gfx::Vector2dF* out_target_position) const override; // Returns the amount of delta that can be applied to scroll_node, taking // page scale into account. @@ -778,7 +779,7 @@ class CC_EXPORT LayerTreeHostImpl // Returns true if status changed. bool UpdateGpuRasterizationStatus(); - void UpdateTreeResourcesForGpuRasterizationIfNeeded(); + void UpdateTreeResourcesIfNeeded(); Viewport* viewport() const { return viewport_.get(); } @@ -1075,7 +1076,7 @@ class CC_EXPORT LayerTreeHostImpl uint32_t next_frame_token_ = 1u; - viz::LocalSurfaceId last_draw_local_surface_id_; + viz::LocalSurfaceIdAllocation last_draw_local_surface_id_allocation_; base::flat_set<viz::SurfaceRange> last_draw_referenced_surfaces_; base::Optional<RenderFrameMetadata> last_draw_render_frame_metadata_; viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_; @@ -1106,10 +1107,15 @@ class CC_EXPORT LayerTreeHostImpl base::circular_deque<FrameTokenInfo> frame_token_infos_; ui::FrameMetrics frame_metrics_; ui::SkippedFrameTracker skipped_frame_tracker_; + int last_color_space_id_ = -1; bool is_animating_for_snap_; const PaintImage::GeneratorClientId paint_image_generator_client_id_; + // Set to true when a scroll gesture being handled on the compositor has + // ended. + bool scroll_gesture_did_end_; + DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl); }; diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index 47732887d78..a31b2fe9444 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -20,6 +20,7 @@ #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "build/build_config.h" #include "cc/animation/animation_host.h" #include "cc/animation/animation_id_provider.h" @@ -54,6 +55,7 @@ #include "cc/test/layer_tree_test.h" #include "cc/test/skia_common.h" #include "cc/test/test_task_graph_runner.h" +#include "cc/trees/clip_node.h" #include "cc/trees/draw_property_utils.h" #include "cc/trees/effect_node.h" #include "cc/trees/latency_info_swap_promise.h" @@ -192,8 +194,10 @@ class LayerTreeHostImplTest : public testing::Test, } void DidActivateSyncTree() override { // Make sure the active tree always has a valid LocalSurfaceId. - host_impl_->active_tree()->SetLocalSurfaceIdFromParent( - viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u))); + host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( + viz::LocalSurfaceIdAllocation( + viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), + base::TimeTicks::Now())); } void WillPrepareTiles() override {} void DidPrepareTiles() override {} @@ -254,8 +258,10 @@ class LayerTreeHostImplTest : public testing::Test, bool init = host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get()); host_impl_->active_tree()->SetDeviceViewportSize(gfx::Size(10, 10)); host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); - host_impl_->active_tree()->SetLocalSurfaceIdFromParent( - viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u))); + host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( + viz::LocalSurfaceIdAllocation( + viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), + base::TimeTicks::Now())); // Set the viz::BeginFrameArgs so that methods which use it are able to. host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( BEGINFRAME_FROM_HERE, 0, 1, @@ -294,7 +300,7 @@ class LayerTreeHostImplTest : public testing::Test, static ::testing::AssertionResult ScrollInfoContains( const ScrollAndScaleSet& scroll_info, ElementId id, - const gfx::Vector2d& scroll_delta) { + const gfx::ScrollOffset& scroll_delta) { int times_encountered = 0; for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) { @@ -960,7 +966,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaTreeButNoChanges) { TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { gfx::ScrollOffset scroll_offset(20, 30); - gfx::Vector2d scroll_delta(11, -15); + gfx::ScrollOffset scroll_delta(11, -15); auto root_owned = LayerImpl::Create(host_impl_->active_tree(), 1); auto* root = root_owned.get(); @@ -977,14 +983,14 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { std::unique_ptr<ScrollAndScaleSet> scroll_info; - root->ScrollBy(scroll_delta); + root->ScrollBy(gfx::ScrollOffsetToVector2dF(scroll_delta)); scroll_info = host_impl_->ProcessScrollDeltas(); ASSERT_EQ(scroll_info->scrolls.size(), 1u); EXPECT_TRUE( ScrollInfoContains(*scroll_info, root->element_id(), scroll_delta)); - gfx::Vector2d scroll_delta2(-5, 27); - root->ScrollBy(scroll_delta2); + gfx::ScrollOffset scroll_delta2(-5, 27); + root->ScrollBy(gfx::ScrollOffsetToVector2dF(scroll_delta2)); scroll_info = host_impl_->ProcessScrollDeltas(); ASSERT_EQ(scroll_info->scrolls.size(), 1u); EXPECT_TRUE(ScrollInfoContains(*scroll_info, root->element_id(), @@ -1128,8 +1134,10 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { // We should still be scrolling, because the scrolled layer also exists in the // new tree. - gfx::Vector2d scroll_delta(0, 10); - host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); + gfx::ScrollOffset scroll_delta(0, 10); + host_impl_->ScrollBy( + UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF(scroll_delta)) + .get()); host_impl_->ScrollEnd(EndState().get()); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -1664,7 +1672,7 @@ TEST_F(LayerTreeHostImplTest, SnapAnimationCancelledByScroll) { EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); BeginImplFrameAndAnimate(begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(150)); - EXPECT_VECTOR_EQ(ScrollOffsetToVector2dF(current_offset), + EXPECT_VECTOR_EQ(gfx::ScrollOffsetToVector2dF(current_offset), overflow->CurrentScrollOffset()); } @@ -2256,7 +2264,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { host_impl_->ProcessScrollDeltas(); EXPECT_TRUE(ScrollInfoContains( *scroll_info.get(), scroll_layer->element_id(), - gfx::Vector2d(0, scroll_delta.y() / page_scale_delta))); + gfx::ScrollOffset(0, scroll_delta.y() / page_scale_delta))); } } @@ -2876,7 +2884,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(-10, -10))); + gfx::ScrollOffset(-10, -10))); } // Two-finger panning should work when starting fully zoomed out. @@ -2910,7 +2918,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, 2.f); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(10, 10))); + gfx::ScrollOffset(10, 10))); } } @@ -2951,7 +2959,7 @@ TEST_F(LayerTreeHostImplTest, SyncSubpixelScrollDelta) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(0, -1))); + gfx::ScrollOffset(0, -1))); // Verify this scroll delta is consistent with the snapped position of the // scroll layer. @@ -3193,7 +3201,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, 2); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(-50, -50))); + gfx::ScrollOffset(-50, -50))); } start_time += base::TimeDelta::FromSeconds(10); @@ -3246,7 +3254,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale); // Pushed to (0,0) via clamping against contents layer size. EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(-50, -50))); + gfx::ScrollOffset(-50, -50))); } } @@ -3432,7 +3440,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, target_scale); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), - gfx::Vector2d(-50, -50))); + gfx::ScrollOffset(-50, -50))); } TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { @@ -3577,8 +3585,10 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { host_impl_->active_tree()->BuildPropertyTreesForTesting(); host_impl_->active_tree()->DidBecomeActive(); host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain(); - host_impl_->active_tree()->SetLocalSurfaceIdFromParent( - viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u))); + host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( + viz::LocalSurfaceIdAllocation( + viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), + base::TimeTicks::Now())); DrawFrame(); // SetScrollElementId will initialize the scrollbar which will cause it to @@ -5369,61 +5379,9 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest { const gfx::Size& inner_viewport_size, const gfx::Size& outer_viewport_size, const gfx::Size& scroll_layer_size) { - tree_impl->set_browser_controls_shrink_blink_size(true); - tree_impl->SetTopControlsHeight(top_controls_height_); - tree_impl->SetCurrentBrowserControlsShownRatio(1.f); - tree_impl->PushPageScaleFromMainThread(1.f, 1.f, 1.f); - host_impl_->DidChangeBrowserControlsPosition(); - - std::unique_ptr<LayerImpl> root = LayerImpl::Create(tree_impl, 1); - std::unique_ptr<LayerImpl> root_clip = LayerImpl::Create(tree_impl, 2); - std::unique_ptr<LayerImpl> page_scale = LayerImpl::Create(tree_impl, 3); - - std::unique_ptr<LayerImpl> outer_scroll = LayerImpl::Create(tree_impl, 4); - std::unique_ptr<LayerImpl> outer_clip = LayerImpl::Create(tree_impl, 5); - - root_clip->SetBounds(inner_viewport_size); - root->SetScrollable(inner_viewport_size); - root->SetElementId(LayerIdToElementIdForTesting(root->id())); - root->SetBounds(outer_viewport_size); - root->SetPosition(gfx::PointF()); - root->SetDrawsContent(false); - root_clip->test_properties()->force_render_surface = true; - root->test_properties()->is_container_for_fixed_position_layers = true; - outer_clip->SetBounds(outer_viewport_size); - outer_scroll->SetScrollable(outer_viewport_size); - outer_scroll->SetElementId( - LayerIdToElementIdForTesting(outer_scroll->id())); - outer_scroll->SetBounds(scroll_layer_size); - outer_scroll->SetPosition(gfx::PointF()); - outer_scroll->SetDrawsContent(false); - outer_scroll->test_properties()->is_container_for_fixed_position_layers = - true; - - int inner_viewport_container_layer_id = root_clip->id(); - int outer_viewport_container_layer_id = outer_clip->id(); - int inner_viewport_scroll_layer_id = root->id(); - int outer_viewport_scroll_layer_id = outer_scroll->id(); - int page_scale_layer_id = page_scale->id(); - - outer_clip->test_properties()->AddChild(std::move(outer_scroll)); - root->test_properties()->AddChild(std::move(outer_clip)); - page_scale->test_properties()->AddChild(std::move(root)); - root_clip->test_properties()->AddChild(std::move(page_scale)); - - tree_impl->SetRootLayerForTesting(std::move(root_clip)); - LayerTreeImpl::ViewportLayerIds viewport_ids; - viewport_ids.page_scale = page_scale_layer_id; - viewport_ids.inner_viewport_container = inner_viewport_container_layer_id; - viewport_ids.outer_viewport_container = outer_viewport_container_layer_id; - viewport_ids.inner_viewport_scroll = inner_viewport_scroll_layer_id; - viewport_ids.outer_viewport_scroll = outer_viewport_scroll_layer_id; - tree_impl->SetViewportLayersFromIds(viewport_ids); - tree_impl->BuildPropertyTreesForTesting(); - - host_impl_->active_tree()->SetDeviceViewportSize(inner_viewport_size); - LayerImpl* root_clip_ptr = tree_impl->root_layer_for_testing(); - EXPECT_EQ(inner_viewport_size, root_clip_ptr->bounds()); + LayerTestCommon::SetupBrowserControlsAndScrollLayerWithVirtualViewport( + host_impl_.get(), tree_impl, top_controls_height_, inner_viewport_size, + outer_viewport_size, scroll_layer_size); } protected: @@ -5508,6 +5466,65 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, host_impl_->ScrollEnd(EndState().get()); } +TEST_F(LayerTreeHostImplBrowserControlsTest, + MovingBrowserControlsChangesViewportClip) { + // TODO(bokan): This test is checking pre-blink-gen-property-tree behavior + // and can be removed once that flag ships. See crbug.com/901083. + if (DefaultSettings().use_layer_lists) + return; + + SetupBrowserControlsAndScrollLayerWithVirtualViewport( + gfx::Size(50, 50), gfx::Size(25, 25), gfx::Size(100, 100)); + + LayerTreeImpl* active_tree = host_impl_->active_tree(); + + // Create a content layer beneath the outer viewport scroll layer. + int id = host_impl_->OuterViewportScrollLayer()->id(); + host_impl_->OuterViewportScrollLayer()->test_properties()->AddChild( + LayerImpl::Create(host_impl_->active_tree(), id + 2)); + LayerImpl* content = + active_tree->OuterViewportScrollLayer()->test_properties()->children[0]; + content->SetBounds(gfx::Size(100, 100)); + host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 2.f, 4.f); + host_impl_->active_tree()->BuildPropertyTreesForTesting(); + + DrawFrame(); + + LayerImpl* inner_container = active_tree->InnerViewportContainerLayer(); + LayerImpl* outer_container = active_tree->OuterViewportContainerLayer(); + LayerImpl* outer_scroll = active_tree->OuterViewportScrollLayer(); + auto* property_trees = host_impl_->active_tree()->property_trees(); + ClipNode* outer_clip_node = + property_trees->clip_tree.Node(outer_scroll->clip_tree_index()); + + // The browser controls should start off showing so the viewport should be + // shrunk. + EXPECT_EQ(50, host_impl_->browser_controls_manager()->ContentTopOffset()); + ASSERT_EQ(gfx::Size(50, 50), inner_container->bounds()); + ASSERT_EQ(gfx::Size(25, 25), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(100, 100), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::SizeF(50, 50), outer_clip_node->clip.size()); + + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) + .thread); + + // Hide the browser controls by 10px. The outer clip should expand by 10px as + // well because the clip node doesn't account for the "resize to + // minimum-scale" that occurs for the outer viewport layer (hence, why the + // outer viewport layer is half the size of the inner in this test). + { + host_impl_->ScrollBy( + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(0.f, 10.f)).get()); + ASSERT_EQ(40, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(gfx::SizeF(50, 60), outer_clip_node->clip.size()); + } + + host_impl_->ScrollEnd(EndState().get()); +} + // Tests that browser controls affect the position of horizontal scrollbars. TEST_F(LayerTreeHostImplBrowserControlsTest, HidingBrowserControlsAdjustsScrollbarPosition) { @@ -5874,8 +5891,6 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // bounds. TEST_F(LayerTreeHostImplBrowserControlsTest, PositionBrowserControlsExplicitly) { - settings_ = DefaultSettings(); - CreateHostImpl(settings_, CreateLayerTreeFrameSink()); SetupBrowserControlsAndScrollLayerWithVirtualViewport( layer_size_, layer_size_, layer_size_); DrawFrame(); @@ -5909,8 +5924,6 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // applied on sync tree activation. The total browser controls offset shouldn't // change after the activation. TEST_F(LayerTreeHostImplBrowserControlsTest, ApplyDeltaOnTreeActivation) { - settings_ = DefaultSettings(); - CreateHostImpl(settings_, CreateLayerTreeFrameSink()); SetupBrowserControlsAndScrollLayerWithVirtualViewport( layer_size_, layer_size_, layer_size_); DrawFrame(); @@ -5959,8 +5972,6 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, ApplyDeltaOnTreeActivation) { // the compositor to accommodate the browser controls. TEST_F(LayerTreeHostImplBrowserControlsTest, BrowserControlsLayoutHeightChanged) { - settings_ = DefaultSettings(); - CreateHostImpl(settings_, CreateLayerTreeFrameSink()); SetupBrowserControlsAndScrollLayerWithVirtualViewport( layer_size_, layer_size_, layer_size_); DrawFrame(); @@ -6197,8 +6208,6 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, TEST_F(LayerTreeHostImplBrowserControlsTest, ScrollNonScrollableRootWithBrowserControls) { - settings_ = DefaultSettings(); - CreateHostImpl(settings_, CreateLayerTreeFrameSink()); SetupBrowserControlsAndScrollLayerWithVirtualViewport( layer_size_, layer_size_, layer_size_); DrawFrame(); @@ -6311,6 +6320,20 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); + // The first animation frame will not produce any delta, it will establish + // the animation. + { + begin_frame_args.frame_time = start_time; + begin_frame_args.sequence_number++; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); + host_impl_->UpdateAnimationState(true); + host_impl_->DidFinishImplFrame(); + float delta = + host_impl_->active_tree()->top_controls_shown_ratio()->Delta(); + ASSERT_EQ(delta, 0); + } + // Pump an animation frame to put some delta in the browser controls. { begin_frame_args.frame_time = @@ -6535,7 +6558,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { EXPECT_EQ(viewport_size, root_container->bounds()); gfx::Vector2d scroll_delta(0, 10); - gfx::Vector2d expected_scroll_delta = scroll_delta; + gfx::ScrollOffset expected_scroll_delta(scroll_delta); LayerImpl* root_scroll = host_impl_->OuterViewportScrollLayer(); gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset(); EXPECT_EQ( @@ -6582,7 +6605,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { EXPECT_EQ(viewport_size, root_container->bounds()); gfx::Vector2d scroll_delta(0, 10); - gfx::Vector2d expected_scroll_delta = scroll_delta; + gfx::ScrollOffset expected_scroll_delta(scroll_delta); LayerImpl* root_scroll = host_impl_->OuterViewportScrollLayer(); gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset(); EXPECT_EQ( @@ -6687,7 +6710,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { DrawFrame(); gfx::Vector2d scroll_delta(0, 10); - gfx::Vector2d expected_scroll_delta(scroll_delta); + gfx::ScrollOffset expected_scroll_delta(scroll_delta); gfx::ScrollOffset expected_max_scroll(outer_scroll->MaxScrollOffset()); EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, @@ -6770,7 +6793,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { ->children[0]; EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), grand_child_layer->element_id(), - gfx::Vector2d(0, -5))); + gfx::ScrollOffset(0, -5))); // The child should not have scrolled. ExpectNone(*scroll_info.get(), child->element_id()); @@ -6947,8 +6970,9 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { ->test_properties() ->children[0]; LayerImpl* grand_child = child->test_properties()->children[0]; - EXPECT_TRUE(ScrollInfoContains( - *scroll_info.get(), grand_child->element_id(), gfx::Vector2d(0, -2))); + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), + grand_child->element_id(), + gfx::ScrollOffset(0, -2))); // The child should not have scrolled. ExpectNone(*scroll_info.get(), child->element_id()); @@ -6971,11 +6995,12 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { // The child should have scrolled up to its limit. EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child->element_id(), - gfx::Vector2d(0, -3))); + gfx::ScrollOffset(0, -3))); // The grand child should not have scrolled. - EXPECT_TRUE(ScrollInfoContains( - *scroll_info.get(), grand_child->element_id(), gfx::Vector2d(0, -2))); + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), + grand_child->element_id(), + gfx::ScrollOffset(0, -2))); // After scrolling the parent, another scroll on the opposite direction // should still scroll the child. @@ -6995,12 +7020,13 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { scroll_info = host_impl_->ProcessScrollDeltas(); // The grand child should have scrolled. - EXPECT_TRUE(ScrollInfoContains( - *scroll_info.get(), grand_child->element_id(), gfx::Vector2d(0, 5))); + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), + grand_child->element_id(), + gfx::ScrollOffset(0, 5))); // The child should not have scrolled. EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child->element_id(), - gfx::Vector2d(0, -3))); + gfx::ScrollOffset(0, -3))); // Scrolling should be adjusted from viewport space. host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 2.f, 2.f); @@ -7020,8 +7046,9 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { scroll_info = host_impl_->ProcessScrollDeltas(); // Should have scrolled by half the amount in layer space (5 - 2/2) - EXPECT_TRUE(ScrollInfoContains( - *scroll_info.get(), grand_child->element_id(), gfx::Vector2d(0, 4))); + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), + grand_child->element_id(), + gfx::ScrollOffset(0, 4))); } } TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { @@ -7064,13 +7091,15 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { host_impl_->active_tree()->SetDeviceViewportSize(surface_size); DrawFrame(); { - gfx::Vector2d scroll_delta(0, 4); + gfx::ScrollOffset scroll_delta(0, 4); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) .thread); - host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); + host_impl_->ScrollBy( + UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF(scroll_delta)) + .get()); host_impl_->ScrollEnd(EndState().get()); std::unique_ptr<ScrollAndScaleSet> scroll_info = @@ -7200,18 +7229,21 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { // The layer should have scrolled down in its local coordinates. std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), scroll_layer->element_id(), - gfx::Vector2d(0, gesture_scroll_delta.x()))); + EXPECT_TRUE( + ScrollInfoContains(*scroll_info.get(), scroll_layer->element_id(), + gfx::ScrollOffset(0, gesture_scroll_delta.x()))); // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF()); - gfx::Vector2d wheel_scroll_delta(0, 10); + gfx::ScrollOffset wheel_scroll_delta(0, 10); EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) .thread); - host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF( + wheel_scroll_delta)) + .get()); host_impl_->ScrollEnd(EndState().get()); // The layer should have scrolled down in its local coordinates. @@ -7271,9 +7303,9 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { // The child layer should have scrolled down in its local coordinates an // amount proportional to the angle between it and the input scroll delta. - gfx::Vector2d expected_scroll_delta( - 0, - gesture_scroll_delta.y() * std::cos(gfx::DegToRad(child_layer_angle))); + gfx::ScrollOffset expected_scroll_delta( + 0, std::floor(gesture_scroll_delta.y() * + std::cos(gfx::DegToRad(child_layer_angle)))); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child_scroll_id, @@ -7297,9 +7329,9 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { // The child layer should have scrolled down in its local coordinates an // amount proportional to the angle between it and the input scroll delta. - gfx::Vector2d expected_scroll_delta( - 0, - -gesture_scroll_delta.x() * std::sin(gfx::DegToRad(child_layer_angle))); + gfx::ScrollOffset expected_scroll_delta( + 0, std::floor(-gesture_scroll_delta.x() * + std::sin(gfx::DegToRad(child_layer_angle)))); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child_scroll_id, @@ -7346,21 +7378,21 @@ TEST_F(LayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) { std::unique_ptr<ScrollAndScaleSet> scroll_info; - gfx::Vector2d gesture_scroll_deltas[4]; - gesture_scroll_deltas[0] = gfx::Vector2d(4, 10); - gesture_scroll_deltas[1] = gfx::Vector2d(4, 10); - gesture_scroll_deltas[2] = gfx::Vector2d(10, 0); - gesture_scroll_deltas[3] = gfx::Vector2d(10, 0); + gfx::ScrollOffset gesture_scroll_deltas[4]; + gesture_scroll_deltas[0] = gfx::ScrollOffset(4, 10); + gesture_scroll_deltas[1] = gfx::ScrollOffset(4, 10); + gesture_scroll_deltas[2] = gfx::ScrollOffset(10, 0); + gesture_scroll_deltas[3] = gfx::ScrollOffset(10, 0); - gfx::Vector2d expected_scroll_deltas[4]; + gfx::ScrollOffset expected_scroll_deltas[4]; // Perspective affects the vertical delta by a different // amount depending on the vertical position of the |viewport_point|. - expected_scroll_deltas[0] = gfx::Vector2d(2, 9); - expected_scroll_deltas[1] = gfx::Vector2d(1, 4); + expected_scroll_deltas[0] = gfx::ScrollOffset(2, 9); + expected_scroll_deltas[1] = gfx::ScrollOffset(1, 4); // Deltas which start with the same vertical position of the // |viewport_point| are subject to identical perspective effects. - expected_scroll_deltas[2] = gfx::Vector2d(5, 0); - expected_scroll_deltas[3] = gfx::Vector2d(5, 0); + expected_scroll_deltas[2] = gfx::ScrollOffset(5, 0); + expected_scroll_deltas[3] = gfx::ScrollOffset(5, 0); gfx::Point viewport_point(1, 1); @@ -7376,8 +7408,11 @@ TEST_F(LayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) { InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy( - UpdateState(viewport_point, gesture_scroll_deltas[i]).get()); - viewport_point += gesture_scroll_deltas[i]; + UpdateState(viewport_point, + gfx::ScrollOffsetToVector2dF(gesture_scroll_deltas[i])) + .get()); + viewport_point += + gfx::ScrollOffsetToFlooredVector2d(gesture_scroll_deltas[i]); host_impl_->ScrollEnd(EndState().get()); scroll_info = host_impl_->ProcessScrollDeltas(); @@ -7420,18 +7455,21 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { // amount. std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), scroll_layer->element_id(), - gfx::Vector2d(0, scroll_delta.y() / scale))); + EXPECT_TRUE( + ScrollInfoContains(*scroll_info.get(), scroll_layer->element_id(), + gfx::ScrollOffset(0, scroll_delta.y() / scale))); // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF()); - gfx::Vector2d wheel_scroll_delta(0, 10); + gfx::ScrollOffset wheel_scroll_delta(0, 10); EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) .thread); - host_impl_->ScrollBy(UpdateState(gfx::Point(), wheel_scroll_delta).get()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF( + wheel_scroll_delta)) + .get()); host_impl_->ScrollEnd(EndState().get()); // It should apply the scale factor to the scroll delta for the wheel event. @@ -7600,7 +7638,8 @@ TEST_F(LayerTreeHostImplTest, host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); EXPECT_FALSE(frame.has_no_damage); - CheckLayerScrollDelta(scroll_layer, ScrollOffsetToVector2dF(scroll_offset)); + CheckLayerScrollDelta(scroll_layer, + gfx::ScrollOffsetToVector2dF(scroll_offset)); } TEST_F(LayerTreeHostImplTest, @@ -7638,7 +7677,7 @@ TEST_F(LayerTreeHostImplTest, host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(frame.has_no_damage); CheckLayerScrollDelta(scroll_layer, - ScrollOffsetToVector2dF(gfx::ScrollOffset())); + gfx::ScrollOffsetToVector2dF(gfx::ScrollOffset())); } TEST_F(LayerTreeHostImplTest, OverscrollRoot) { @@ -9284,8 +9323,10 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { root->test_properties()->AddChild(std::move(child)); layer_tree_host_impl->active_tree()->SetRootLayerForTesting(std::move(root)); layer_tree_host_impl->active_tree()->BuildPropertyTreesForTesting(); - layer_tree_host_impl->active_tree()->SetLocalSurfaceIdFromParent( - viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u))); + layer_tree_host_impl->active_tree()->SetLocalSurfaceIdAllocationFromParent( + viz::LocalSurfaceIdAllocation( + viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), + base::TimeTicks::Now())); TestFrameData frame; @@ -9854,6 +9895,11 @@ TEST_F(LayerTreeHostImplTest, RequireHighResAfterGpuRasterizationToggles) { // RequiresHighResToDraw is set when new output surface is used. EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); + // The first commit will also set RequiresHighResToDraw due to the + // raster color space changing. + host_impl_->ResetRequiresHighResToDraw(); + host_impl_->CommitComplete(); + EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); host_impl_->ResetRequiresHighResToDraw(); host_impl_->SetContentHasSlowPaths(false); @@ -10026,9 +10072,8 @@ class FrameSinkClient : public viz::TestLayerTreeFrameSinkClient { const viz::LocalSurfaceId& local_surface_id) override {} void DisplayReceivedCompositorFrame( const viz::CompositorFrame& frame) override {} - void DisplayWillDrawAndSwap( - bool will_draw_and_swap, - const viz::RenderPassList& render_passes) override {} + void DisplayWillDrawAndSwap(bool will_draw_and_swap, + viz::RenderPassList* render_passes) override {} void DisplayDidDrawAndSwap() override {} private: @@ -13737,7 +13782,8 @@ class TestRenderFrameMetadataObserver : public RenderFrameMetadataObserver { void BindToCurrentThread() override {} void OnRenderFrameSubmission( const RenderFrameMetadata& render_frame_metadata, - viz::CompositorFrameMetadata* compositor_frame_metadata) override { + viz::CompositorFrameMetadata* compositor_frame_metadata, + bool force_send) override { if (increment_counter_) compositor_frame_metadata->send_frame_token_to_embedder = true; last_metadata_ = render_frame_metadata; diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc index 1c95b6fcf4e..9c800d93374 100644 --- a/chromium/cc/trees/layer_tree_host_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_perftest.cc @@ -148,7 +148,7 @@ class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest { void BuildTree() override { gfx::Size viewport = gfx::Size(720, 1038); layer_tree_host()->SetViewportSizeAndScale(viewport, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); scoped_refptr<Layer> root = ParseTreeFromJson(json_, &fake_content_layer_client_); ASSERT_TRUE(root.get()); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc index 93dee1acd3d..39499795006 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc @@ -294,7 +294,7 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRoot) { RunPixelResourceTest(background, expected); } -TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { +TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackdropFilter) { const int kRootWidth = 2; const int kRootHeight = 2; InitializeFromTestCase(resource_type()); @@ -302,7 +302,7 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange); - // Orange child layers have a background filter set and they will blend with + // Orange child layers have a backdrop filter set and they will blend with // the green background gfx::Rect child_rect(0, 0, kRootWidth, kRootHeight); scoped_refptr<SolidColorLayer> green_lane = @@ -310,7 +310,7 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { background->AddChild(green_lane); FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(.75)); - green_lane->SetBackgroundFilters(filters); + green_lane->SetBackdropFilters(filters); green_lane->SetBlendMode(current_blend_mode()); SkBitmap expected; diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index 378d4338879..67e3b25aefc 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -19,11 +19,11 @@ namespace { class LayerTreeHostFiltersPixelTest : public LayerTreePixelTest {}; -TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlur) { +TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlur) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); - // The green box is entirely behind a layer with background blur, so it + // The green box is entirely behind a layer with backdrop blur, so it // should appear blurred on its edges. scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer( gfx::Rect(50, 50, 100, 100), kCSSGreen); @@ -35,7 +35,7 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlur) { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter( 2.f, SkBlurImageFilter::kClamp_TileMode)); - blur->SetBackgroundFilters(filters); + blur->SetBackdropFilters(filters); #if defined(OS_WIN) || defined(ARCH_CPU_ARM64) // Windows and ARM64 have 436 pixels off by 1: crbug.com/259915 @@ -53,17 +53,16 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlur) { small_error_allowed)); #endif - RunPixelTest(PIXEL_TEST_GL, - background, - base::FilePath(FILE_PATH_LITERAL("background_filter_blur.png"))); + RunPixelTest(PIXEL_TEST_GL, background, + base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur.png"))); } -TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) { +TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); - // The green border is outside the layer with background blur, but the - // background blur should use pixels from outside its layer borders, up to the + // The green border is outside the layer with backdrop blur, but the + // backdrop blur should use pixels from outside its layer borders, up to the // radius of the blur effect. So the border should be blurred underneath the // top layer causing the green to bleed under the transparent layer, but not // in the 1px region between the transparent layer and the green border. @@ -77,7 +76,7 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter( 5.f, SkBlurImageFilter::kClamp_TileMode)); - blur->SetBackgroundFilters(filters); + blur->SetBackdropFilters(filters); #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) || defined(ARCH_CPU_ARM64) @@ -101,12 +100,11 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) { #endif RunPixelTest( - PIXEL_TEST_GL, - background, - base::FilePath(FILE_PATH_LITERAL("background_filter_blur_outsets.png"))); + PIXEL_TEST_GL, background, + base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_outsets.png"))); } -TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { +TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOffAxis) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorTRANSPARENT); @@ -144,7 +142,7 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter( 2.f, SkBlurImageFilter::kClamp_TileMode)); - blur->SetBackgroundFilters(filters); + blur->SetBackdropFilters(filters); #if defined(OS_WIN) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -168,9 +166,8 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { #endif RunPixelTest( - PIXEL_TEST_GL, - background, - base::FilePath(FILE_PATH_LITERAL("background_filter_blur_off_axis.png"))); + PIXEL_TEST_GL, background, + base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_off_axis.png"))); } class LayerTreeHostFiltersScaledPixelTest @@ -384,7 +381,7 @@ TEST_F(ImageFilterNonZeroOriginPixelTest, ImageFilterNonZeroOrigin_Software) { RunPixelTestType(PIXEL_TEST_SOFTWARE); } -class ImageScaledBackgroundFilter : public LayerTreeHostFiltersPixelTest { +class ImageScaledBackdropFilter : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { scoped_refptr<SolidColorLayer> background = @@ -422,7 +419,7 @@ class ImageScaledBackgroundFilter : public LayerTreeHostFiltersPixelTest { FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f)); - filter->SetBackgroundFilters(filters); + filter->SetBackdropFilters(filters); #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -451,19 +448,19 @@ class ImageScaledBackgroundFilter : public LayerTreeHostFiltersPixelTest { } }; -TEST_F(ImageScaledBackgroundFilter, ImageFilterScaled_GL) { +TEST_F(ImageScaledBackdropFilter, ImageFilterScaled_GL) { RunPixelTestType(PIXEL_TEST_GL, base::FilePath(FILE_PATH_LITERAL( - "background_filter_on_scaled_layer_gl.png"))); + "backdrop_filter_on_scaled_layer_gl.png"))); } -TEST_F(ImageScaledBackgroundFilter, ImageFilterScaled_Software) { +TEST_F(ImageScaledBackdropFilter, ImageFilterScaled_Software) { RunPixelTestType(PIXEL_TEST_SOFTWARE, base::FilePath(FILE_PATH_LITERAL( - "background_filter_on_scaled_layer_sw.png"))); + "backdrop_filter_on_scaled_layer_sw.png"))); } -class ImageBackgroundFilter : public LayerTreeHostFiltersPixelTest { +class ImageBackdropFilter : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { // Add a white background with a rotated red rect in the center. @@ -499,7 +496,7 @@ class ImageBackgroundFilter : public LayerTreeHostFiltersPixelTest { FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter( 5.0f, SkBlurImageFilter::kClamp_TileMode)); - filter->SetBackgroundFilters(filters); + filter->SetBackdropFilters(filters); // Allow some fuzziness so that this doesn't fail when Skia makes minor // changes to blur or rectangle rendering. @@ -518,16 +515,16 @@ class ImageBackgroundFilter : public LayerTreeHostFiltersPixelTest { } }; -TEST_F(ImageBackgroundFilter, BackgroundFilterRotated_GL) { +TEST_F(ImageBackdropFilter, BackdropFilterRotated_GL) { RunPixelTestType( PIXEL_TEST_GL, - base::FilePath(FILE_PATH_LITERAL("background_filter_rotated_gl.png"))); + base::FilePath(FILE_PATH_LITERAL("backdrop_filter_rotated_gl.png"))); } -TEST_F(ImageBackgroundFilter, BackgroundFilterRotated_Software) { +TEST_F(ImageBackdropFilter, BackdropFilterRotated_Software) { RunPixelTestType( PIXEL_TEST_SOFTWARE, - base::FilePath(FILE_PATH_LITERAL("background_filter_rotated_sw.png"))); + base::FilePath(FILE_PATH_LITERAL("backdrop_filter_rotated_sw.png"))); } class ImageScaledRenderSurface : public LayerTreeHostFiltersPixelTest { @@ -615,7 +612,7 @@ class ZoomFilterTest : public LayerTreeHostFiltersPixelTest { FilterOperations border_filters; border_filters.Append( FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */)); - border_edge_zoom->SetBackgroundFilters(border_filters); + border_edge_zoom->SetBackdropFilters(border_filters); root->AddChild(border_edge_zoom); // Test a zoom that extends past the edge of the screen. @@ -624,7 +621,7 @@ class ZoomFilterTest : public LayerTreeHostFiltersPixelTest { FilterOperations top_filters; top_filters.Append( FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */)); - top_edge_zoom->SetBackgroundFilters(top_filters); + top_edge_zoom->SetBackdropFilters(top_filters); root->AddChild(top_edge_zoom); // Test a zoom that is fully within the screen. @@ -633,7 +630,7 @@ class ZoomFilterTest : public LayerTreeHostFiltersPixelTest { FilterOperations mid_filters; mid_filters.Append( FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */)); - contained_zoom->SetBackgroundFilters(mid_filters); + contained_zoom->SetBackdropFilters(mid_filters); root->AddChild(contained_zoom); #if defined(OS_WIN) @@ -1056,7 +1053,7 @@ TEST_F(FilterWithGiantCropRectNoClip, GL) { base::FilePath(FILE_PATH_LITERAL("filter_with_giant_crop_rect.png"))); } -class BackgroundFilterWithDeviceScaleFactorTest +class BackdropFilterWithDeviceScaleFactorTest : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(float device_scale_factor, @@ -1076,7 +1073,7 @@ class BackgroundFilterWithDeviceScaleFactorTest FilterOperations filters; filters.Append(FilterOperation::CreateReferenceFilter( sk_make_sp<OffsetPaintFilter>(0, 80, nullptr))); - filtered->SetBackgroundFilters(filters); + filtered->SetBackdropFilters(filters); root->AddChild(filtered); // This should appear as a grid of 4 100x100 squares which are: @@ -1102,28 +1099,28 @@ class BackgroundFilterWithDeviceScaleFactorTest float device_scale_factor_ = 1; }; -TEST_F(BackgroundFilterWithDeviceScaleFactorTest, StandardDpi_GL) { +TEST_F(BackdropFilterWithDeviceScaleFactorTest, StandardDpi_GL) { RunPixelTestType( 1.f, PIXEL_TEST_GL, - base::FilePath(FILE_PATH_LITERAL("offset_background_filter_1x.png"))); + base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_1x.png"))); } -TEST_F(BackgroundFilterWithDeviceScaleFactorTest, StandardDpi_Software) { +TEST_F(BackdropFilterWithDeviceScaleFactorTest, StandardDpi_Software) { RunPixelTestType( 1.f, PIXEL_TEST_SOFTWARE, - base::FilePath(FILE_PATH_LITERAL("offset_background_filter_1x.png"))); + base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_1x.png"))); } -TEST_F(BackgroundFilterWithDeviceScaleFactorTest, HiDpi_GL) { +TEST_F(BackdropFilterWithDeviceScaleFactorTest, HiDpi_GL) { RunPixelTestType( 2.f, PIXEL_TEST_GL, - base::FilePath(FILE_PATH_LITERAL("offset_background_filter_2x.png"))); + base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_2x.png"))); } -TEST_F(BackgroundFilterWithDeviceScaleFactorTest, HiDpi_Software) { +TEST_F(BackdropFilterWithDeviceScaleFactorTest, HiDpi_Software) { RunPixelTestType( 2.f, PIXEL_TEST_SOFTWARE, - base::FilePath(FILE_PATH_LITERAL("offset_background_filter_2x.png"))); + base::FilePath(FILE_PATH_LITERAL("offset_backdrop_filter_2x.png"))); } } // namespace diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc index 6732d5e21a6..4639cb3cd2e 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc @@ -267,19 +267,19 @@ class CircleContentLayerClient : public ContentLayerClient { gfx::Size bounds_; }; -using LayerTreeHostMasksForBackgroundFiltersPixelTest = +using LayerTreeHostMasksForBackdropFiltersPixelTest = ParameterizedPixelResourceTest; INSTANTIATE_TEST_CASE_P( PixelResourceTest, - LayerTreeHostMasksForBackgroundFiltersPixelTest, + LayerTreeHostMasksForBackdropFiltersPixelTest, ::testing::Combine( ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY), ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK, Layer::LayerMaskType::MULTI_TEXTURE_MASK))); -TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, - MaskOfLayerWithBackgroundFilter) { +TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, + MaskOfLayerWithBackdropFilter) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(100, 100), SK_ColorWHITE); @@ -296,7 +296,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); - blur->SetBackgroundFilters(filters); + blur->SetBackdropFilters(filters); gfx::Size mask_bounds(100, 100); CircleContentLayerClient mask_client(mask_bounds); @@ -322,14 +322,12 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, base::FilePath image_name = (test_case_ == GPU) - ? base::FilePath( - FILE_PATH_LITERAL("mask_of_background_filter_gpu.png")) - : base::FilePath(FILE_PATH_LITERAL("mask_of_background_filter.png")); + ? base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter_gpu.png")) + : base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter.png")); RunPixelResourceTest(background, image_name); } -TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, - MaskOfLayerWithBlend) { +TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, MaskOfLayerWithBlend) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(128, 128), SK_ColorWHITE); @@ -733,8 +731,8 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircleUnderflow) { RunPixelResourceTest(root, image_name); } -TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, - MaskOfLayerWithBackgroundFilterAndBlend) { +TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, + MaskOfLayerWithBackdropFilterAndBlend) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(128, 128), SK_ColorWHITE); @@ -757,7 +755,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); - picture_horizontal->SetBackgroundFilters(filters); + picture_horizontal->SetBackdropFilters(filters); background->AddChild(picture_vertical); background->AddChild(picture_horizontal); @@ -783,7 +781,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, RunPixelResourceTest(background, base::FilePath(FILE_PATH_LITERAL( - "mask_of_background_filter_and_blend.png"))); + "mask_of_backdrop_filter_and_blend.png"))); } } // namespace diff --git a/chromium/cc/trees/layer_tree_host_single_thread_client.h b/chromium/cc/trees/layer_tree_host_single_thread_client.h index 416b5de8bd6..a648ed5a45e 100644 --- a/chromium/cc/trees/layer_tree_host_single_thread_client.h +++ b/chromium/cc/trees/layer_tree_host_single_thread_client.h @@ -5,6 +5,8 @@ #ifndef CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_ #define CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_ +#include "base/time/time.h" + namespace cc { class LayerTreeHostSingleThreadClient { @@ -15,6 +17,10 @@ class LayerTreeHostSingleThreadClient { // delay for potential future frame. virtual void RequestScheduleAnimation() {} + // Called whenever the begin frame interval changes. This interval can be used + // for animations. + virtual void FrameIntervalUpdated(base::TimeDelta interval) {} + // Called whenever the compositor submits a CompositorFrame. Afterward, // LayerTreeHostClient::DidReceiveCompositorFrameAck() will be called once the // display compositor/ finishes processing the frame. So these functions can diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index d71fdf95d32..97e682c6c82 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -16,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "build/build_config.h" #include "cc/animation/timing_function.h" #include "cc/input/scroll_elasticity_helper.h" @@ -1316,7 +1317,7 @@ class LayerTreeHostTestNoDamageCausesNoInvalidate : public LayerTreeHostTest { root_ = Layer::Create(); layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->SetRootLayer(root_); @@ -1413,7 +1414,7 @@ class LayerTreeHostTestEarlyDamageCheckStops : public LayerTreeHostTest { root_->AddChild(child_); layer_tree_host()->SetViewportSizeAndScale(gfx::Size(100, 100), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->SetRootLayer(root_); root_->SetBounds(gfx::Size(50, 50)); @@ -1501,7 +1502,7 @@ class LayerTreeHostTestPrepareTilesWithoutDraw : public LayerTreeHostTest { layer_tree_host()->root_layer()->AddChild(child_layer_); layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->root_layer()->SetBounds(gfx::Size(50, 50)); child_layer_->SetBounds(gfx::Size(50, 50)); @@ -2333,7 +2334,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest { root_layer_->SetBounds(bounds_); layer_tree_host()->SetRootLayer(root_layer_); layer_tree_host()->SetViewportSizeAndScale(bounds_, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); client_.set_bounds(root_layer_->bounds()); } @@ -2398,7 +2399,7 @@ class LayerTreeHostTestGpuRasterDeviceSizeChanged : public LayerTreeHostTest { root_layer_->SetBounds(bounds_); layer_tree_host()->SetRootLayer(root_layer_); layer_tree_host()->SetViewportSizeAndScale(bounds_, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); client_.set_bounds(root_layer_->bounds()); @@ -2433,8 +2434,8 @@ class LayerTreeHostTestGpuRasterDeviceSizeChanged : public LayerTreeHostTest { void DidCommitAndDrawFrame() override { // On the second commit, resize the viewport. if (num_draws_ == 1) { - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(400, 64), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(400, 64), 1.f, viz::LocalSurfaceIdAllocation()); } if (num_draws_ < 2) { layer_tree_host()->SetNeedsRedrawRect(invalid_rect_); @@ -2549,7 +2550,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate // a second commit as a result. layer_tree_host()->SetViewportSizeAndScale( layer_tree_host()->device_viewport_size(), 4.f, - layer_tree_host()->local_surface_id_from_parent()); + layer_tree_host()->local_surface_id_allocation_from_parent()); break; default: // No extra commits. @@ -2594,7 +2595,7 @@ class LayerTreeHostTestDeviceScaleFactorChange : public LayerTreeHostTest { if (layer_tree_host()->SourceFrameNumber() == 1) { layer_tree_host()->SetViewportSizeAndScale( layer_tree_host()->device_viewport_size(), 4.f, - layer_tree_host()->local_surface_id_from_parent()); + layer_tree_host()->local_surface_id_allocation_from_parent()); } } @@ -2773,7 +2774,7 @@ class LayerTreeHostTestSetNeedsCommitWithForcedRedraw root_layer_->SetBounds(bounds_); layer_tree_host()->SetRootLayer(root_layer_); layer_tree_host()->SetViewportSizeAndScale(bounds_, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); client_.set_bounds(root_layer_->bounds()); } @@ -3062,7 +3063,7 @@ class LayerTreeHostTestCommit : public LayerTreeHostTest { void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(20, 20), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->set_background_color(SK_ColorGRAY); layer_tree_host()->SetEventListenerProperties( EventListenerClass::kMouseWheel, EventListenerProperties::kPassive); @@ -3110,7 +3111,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(20, 20), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->set_background_color(SK_ColorGRAY); PostSetNeedsCommitToMainThread(); @@ -3164,7 +3165,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest { void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(20, 20), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->set_background_color(SK_ColorGRAY); PostSetNeedsCommitToMainThread(); @@ -3236,8 +3237,7 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest { void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { gfx::ScrollOffset offset = scroll_layer_->CurrentScrollOffset(); - scroll_layer_->SetScrollOffset( - ScrollOffsetWithDelta(offset, args.inner_delta)); + scroll_layer_->SetScrollOffset(offset + args.inner_delta); layer_tree_host()->SetPageScaleFactorAndLimits(args.page_scale_delta, 0.5f, 2.f); } @@ -3323,7 +3323,7 @@ class ViewportDeltasAppliedDuringPinch : public LayerTreeHostTest { void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { EXPECT_TRUE(sent_gesture_); - EXPECT_EQ(gfx::Vector2dF(50, 50), args.inner_delta); + EXPECT_EQ(gfx::ScrollOffset(50, 50), args.inner_delta); EXPECT_EQ(2, args.page_scale_delta); auto* scroll_layer = layer_tree_host()->inner_viewport_scroll_layer(); @@ -3379,7 +3379,7 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers child_layer_ = FakePictureLayer::Create(&client_); layer_tree_host()->SetViewportSizeAndScale(gfx::Size(60, 60), 1.5f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); EXPECT_EQ(gfx::Size(60, 60), layer_tree_host()->device_viewport_size()); root_layer_->AddChild(child_layer_); @@ -3476,7 +3476,7 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest { void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); layer_ = FakePictureLayer::Create(&client_); @@ -3520,13 +3520,13 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest { SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate); -class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { +class LayerTreeHostTestDeferMainFrameUpdate : public LayerTreeHostTest { public: - LayerTreeHostTestDeferCommits() = default; + LayerTreeHostTestDeferMainFrameUpdate() = default; void BeginTest() override { // Start with commits deferred. - PostGetDeferCommitsToMainThread(&scoped_defer_commits_); + PostGetDeferMainFrameUpdateToMainThread(&scoped_defer_main_frame_update_); PostSetNeedsCommitToMainThread(); } @@ -3549,7 +3549,7 @@ class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { FROM_HERE, // Unretained because the test should not end before allowing // commits via this running. - base::BindOnce(&LayerTreeHostTestDeferCommits::AllowCommits, + base::BindOnce(&LayerTreeHostTestDeferMainFrameUpdate::AllowCommits, base::Unretained(this))); break; default: @@ -3560,7 +3560,7 @@ class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { } void WillBeginMainFrame() override { - EXPECT_FALSE(scoped_defer_commits_); + EXPECT_FALSE(scoped_defer_main_frame_update_); EXPECT_TRUE(IsCommitAllowed()); num_send_begin_main_frame_++; EndTest(); @@ -3573,24 +3573,24 @@ class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { virtual void AllowCommits() { allow_commits_ = true; - scoped_defer_commits_.reset(); + scoped_defer_main_frame_update_.reset(); } virtual bool IsCommitAllowed() const { return allow_commits_; } private: - std::unique_ptr<ScopedDeferCommits> scoped_defer_commits_; + std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; bool allow_commits_ = false; int num_will_begin_impl_frame_ = 0; int num_send_begin_main_frame_ = 0; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferMainFrameUpdate); // This verifies that changing the size of a LayerTreeHost without providing a // LocalSurfaceId defers commits. class LayerTreeHostInvalidLocalSurfaceIdDefersCommit - : public LayerTreeHostTestDeferCommits { + : public LayerTreeHostTestDeferMainFrameUpdate { public: LayerTreeHostInvalidLocalSurfaceIdDefersCommit() = default; void InitializeSettings(LayerTreeSettings* settings) override { @@ -3605,15 +3605,17 @@ class LayerTreeHostInvalidLocalSurfaceIdDefersCommit void BeginTest() override { PostSetNeedsCommitToMainThread(); } void AllowCommits() override { - local_surface_id_ = allocator_.GenerateId(); - PostSetLocalSurfaceIdToMainThread(local_surface_id_); + allocator_.GenerateId(); + PostSetLocalSurfaceIdAllocationToMainThread( + allocator_.GetCurrentLocalSurfaceIdAllocation()); } - bool IsCommitAllowed() const override { return local_surface_id_.is_valid(); } + bool IsCommitAllowed() const override { + return allocator_.GetCurrentLocalSurfaceIdAllocation().IsValid(); + } private: viz::ParentLocalSurfaceIdAllocator allocator_; - viz::LocalSurfaceId local_surface_id_; }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostInvalidLocalSurfaceIdDefersCommit); @@ -3621,10 +3623,13 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostInvalidLocalSurfaceIdDefersCommit); // This verifies that we can abort a commit inside the main frame, and // we don't leave any weird states around if we never allow the commit // to happen. -class LayerTreeHostTestDeferCommitsInsideBeginMainFrame +// TODO(schenney): This should be renamed back to +// LayerTreeHostTestDeferCommitInsideBeginMainFrame when we re-create +// the concept of defer commit when not defering main frame updates. +class LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame : public LayerTreeHostTest { public: - LayerTreeHostTestDeferCommitsInsideBeginMainFrame() = default; + LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame() = default; void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -3632,7 +3637,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrame ++begin_main_frame_count_; // This should prevent the commit from happening. - scoped_defer_commits_ = layer_tree_host()->DeferCommits(); + scoped_defer_main_frame_update_ = layer_tree_host()->DeferMainFrameUpdate(); // Wait to see if the commit happens. It's possible the deferred // commit happens when it shouldn't but takes long enough that // this passes. But it won't fail when it shouldn't. @@ -3651,20 +3656,24 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrame } private: - std::unique_ptr<ScopedDeferCommits> scoped_defer_commits_; + std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; int commit_count_ = 0; int begin_main_frame_count_ = 0; }; SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostTestDeferCommitsInsideBeginMainFrame); + LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame); // This verifies that we can abort a commit inside the main frame, and // we will finish the commit once it is allowed. -class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter +// TODO(schenney): This should be renamed back to +// LayerTreeHostTestDeferCommitInsideBeginMainFrameWithCommitAfter when +// we re-create the concept of defer commit when not defering main frame +// updates. +class LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter : public LayerTreeHostTest { public: - LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter() = default; + LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter() = default; void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -3674,7 +3683,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter return; // This should prevent the commit from happening. - scoped_defer_commits_ = layer_tree_host()->DeferCommits(); + scoped_defer_main_frame_update_ = layer_tree_host()->DeferMainFrameUpdate(); // Wait to see if the commit happens. It's possible the deferred // commit happens when it shouldn't but takes long enough that // this passes. But it won't fail when it shouldn't. @@ -3682,7 +3691,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter FROM_HERE, // Unretained because the test doesn't end before this runs. base::BindOnce( - &LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter:: + &LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter:: AllowCommits, base::Unretained(this)), base::TimeDelta::FromMilliseconds(100)); @@ -3692,7 +3701,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter // Once we've waited and seen that commit did not happen, we // allow commits and should see this one go through. allow_commits_ = true; - scoped_defer_commits_.reset(); + scoped_defer_main_frame_update_.reset(); } void DidCommit() override { @@ -3713,7 +3722,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter } private: - std::unique_ptr<ScopedDeferCommits> scoped_defer_commits_; + std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; bool allow_commits_ = false; int commit_count_ = 0; int begin_main_frame_count_ = 0; @@ -3721,7 +3730,7 @@ class LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter }; SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostTestDeferCommitsInsideBeginMainFrameWithCommitAfter); + LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter); // This verifies that animate_only BeginFrames only run animation/layout // updates, i.e. abort commits after the paint stage and only request layer @@ -4480,8 +4489,8 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { ++expected_push_properties_grandchild_; break; case 10: - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(20, 20), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(20, 20), 1.f, viz::LocalSurfaceIdAllocation()); // No layers need commit. break; case 11: @@ -5503,7 +5512,7 @@ class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest { // The viewport is empty, but we still need to update layers on the main // thread. layer_tree_host()->SetViewportSizeAndScale(gfx::Size(0, 0), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); } @@ -5835,7 +5844,7 @@ class LayerTreeHostTestKeepSwapPromise : public LayerTreeHostTest { layer_tree_host()->SetRootLayer(layer_); gfx::Size bounds(100, 100); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); } @@ -5932,7 +5941,7 @@ class LayerTreeHostTestKeepSwapPromiseMFBA : public LayerTreeHostTest { layer_tree_host()->SetRootLayer(layer_); gfx::Size bounds(100, 100); layer_tree_host()->SetViewportSizeAndScale(bounds, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); } @@ -6873,13 +6882,13 @@ class LayerTreeHostTestRenderSurfaceEffectTreeIndex : public LayerTreeHostTest { case 2: // Setting an empty viewport causes draws to get skipped, so the active // tree won't update draw properties. - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); child_->SetForceRenderSurfaceForTesting(false); break; case 3: - layer_tree_host()->SetViewportSizeAndScale(root_->bounds(), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + root_->bounds(), 1.f, viz::LocalSurfaceIdAllocation()); } } @@ -7019,6 +7028,8 @@ class LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { EXPECT_EQ(info_.page_scale_delta, args.page_scale_delta); EXPECT_EQ(info_.top_controls_delta, args.browser_controls_delta); + EXPECT_EQ(info_.browser_controls_constraint, + args.browser_controls_constraint); deltas_sent_to_client_ = true; } @@ -7316,7 +7327,7 @@ class GpuRasterizationRasterizesBorderTiles : public LayerTreeHostTest { layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); layer_tree_host()->SetViewportSizeAndScale(viewport_size_, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); client_.set_bounds(root->bounds()); } @@ -7542,7 +7553,7 @@ class LayerTreeHostTestOneActivatePerPrepareTiles : public LayerTreeHostTest { void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(16, 16), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); PostSetNeedsCommitToMainThread(); } @@ -7914,28 +7925,33 @@ class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest { } void BeginTest() override { - expected_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId(); - PostSetLocalSurfaceIdToMainThread(expected_local_surface_id_); + allocator_.GenerateId(); + expected_local_surface_id_allocation_ = + allocator_.GetCurrentLocalSurfaceIdAllocation(); + PostSetLocalSurfaceIdAllocationToMainThread( + expected_local_surface_id_allocation_); } DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, LayerTreeHostImpl::FrameData* frame_data, DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - EXPECT_EQ(expected_local_surface_id_, - host_impl->active_tree()->local_surface_id_from_parent()); + EXPECT_EQ( + expected_local_surface_id_allocation_, + host_impl->active_tree()->local_surface_id_allocation_from_parent()); return draw_result; } void DisplayReceivedLocalSurfaceIdOnThread( const viz::LocalSurfaceId& local_surface_id) override { - EXPECT_EQ(expected_local_surface_id_, local_surface_id); + EXPECT_EQ(expected_local_surface_id_allocation_.local_surface_id(), + local_surface_id); EndTest(); } void AfterTest() override {} - viz::LocalSurfaceId expected_local_surface_id_; + viz::LocalSurfaceIdAllocation expected_local_surface_id_allocation_; viz::ParentLocalSurfaceIdAllocator allocator_; }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLocalSurfaceId); @@ -7949,12 +7965,20 @@ class LayerTreeHostTestLocalSurfaceIdSkipChildNum : public LayerTreeHostTest { } void BeginTest() override { - expected_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId(); - EXPECT_TRUE(child_allocator_.UpdateFromParent(expected_local_surface_id_)); - child_local_surface_id_ = child_allocator_.GenerateId(); - EXPECT_NE(expected_local_surface_id_, child_local_surface_id_); - PostSetLocalSurfaceIdToMainThread(expected_local_surface_id_); - PostSetLocalSurfaceIdToMainThread(child_local_surface_id_); + allocator_.GenerateId(); + expected_local_surface_id_allocation_ = + allocator_.GetCurrentLocalSurfaceIdAllocation(); + EXPECT_TRUE(child_allocator_.UpdateFromParent( + allocator_.GetCurrentLocalSurfaceIdAllocation())); + child_allocator_.GenerateId(); + child_local_surface_id_allocation_ = + child_allocator_.GetCurrentLocalSurfaceIdAllocation(); + EXPECT_NE(expected_local_surface_id_allocation_, + child_local_surface_id_allocation_); + PostSetLocalSurfaceIdAllocationToMainThread( + expected_local_surface_id_allocation_); + PostSetLocalSurfaceIdAllocationToMainThread( + child_local_surface_id_allocation_); } DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, @@ -7962,21 +7986,23 @@ class LayerTreeHostTestLocalSurfaceIdSkipChildNum : public LayerTreeHostTest { DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); // We should not be picking up the newer |child_local_surface_id_|. - EXPECT_EQ(expected_local_surface_id_, - host_impl->active_tree()->local_surface_id_from_parent()); + EXPECT_EQ( + expected_local_surface_id_allocation_, + host_impl->active_tree()->local_surface_id_allocation_from_parent()); return draw_result; } void DisplayReceivedLocalSurfaceIdOnThread( const viz::LocalSurfaceId& local_surface_id) override { - EXPECT_EQ(expected_local_surface_id_, local_surface_id); + EXPECT_EQ(expected_local_surface_id_allocation_.local_surface_id(), + local_surface_id); EndTest(); } void AfterTest() override {} - viz::LocalSurfaceId expected_local_surface_id_; - viz::LocalSurfaceId child_local_surface_id_; + viz::LocalSurfaceIdAllocation expected_local_surface_id_allocation_; + viz::LocalSurfaceIdAllocation child_local_surface_id_allocation_; viz::ParentLocalSurfaceIdAllocator allocator_; viz::ChildLocalSurfaceIdAllocator child_allocator_; }; @@ -7991,8 +8017,11 @@ class LayerTreeHostTestRequestNewLocalSurfaceId : public LayerTreeHostTest { } void BeginTest() override { - expected_parent_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId(); - PostSetLocalSurfaceIdToMainThread(expected_parent_local_surface_id_); + allocator_.GenerateId(); + expected_parent_local_surface_id_allocation_ = + allocator_.GetCurrentLocalSurfaceIdAllocation(); + PostSetLocalSurfaceIdAllocationToMainThread( + expected_parent_local_surface_id_allocation_); PostRequestNewLocalSurfaceIdToMainThread(); } @@ -8000,18 +8029,21 @@ class LayerTreeHostTestRequestNewLocalSurfaceId : public LayerTreeHostTest { LayerTreeHostImpl::FrameData* frame_data, DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - EXPECT_EQ(expected_parent_local_surface_id_, - host_impl->active_tree()->local_surface_id_from_parent()); + EXPECT_EQ( + expected_parent_local_surface_id_allocation_, + host_impl->active_tree()->local_surface_id_allocation_from_parent()); return draw_result; } void DisplayReceivedLocalSurfaceIdOnThread( const viz::LocalSurfaceId& local_surface_id) override { + const viz::LocalSurfaceId& expected_parent_local_surface_id = + expected_parent_local_surface_id_allocation_.local_surface_id(); viz::LocalSurfaceId child_local_surface_id( - expected_parent_local_surface_id_.parent_sequence_number(), - expected_parent_local_surface_id_.child_sequence_number() + 1, - expected_parent_local_surface_id_.embed_token()); - EXPECT_NE(expected_parent_local_surface_id_, local_surface_id); + expected_parent_local_surface_id.parent_sequence_number(), + expected_parent_local_surface_id.child_sequence_number() + 1, + expected_parent_local_surface_id.embed_token()); + EXPECT_NE(expected_parent_local_surface_id, local_surface_id); EXPECT_EQ(child_local_surface_id, local_surface_id); } @@ -8025,7 +8057,7 @@ class LayerTreeHostTestRequestNewLocalSurfaceId : public LayerTreeHostTest { void AfterTest() override {} - viz::LocalSurfaceId expected_parent_local_surface_id_; + viz::LocalSurfaceIdAllocation expected_parent_local_surface_id_allocation_; viz::ParentLocalSurfaceIdAllocator allocator_; }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestNewLocalSurfaceId); @@ -8071,7 +8103,7 @@ class GpuRasterizationSucceedsWithLargeImage : public LayerTreeHostTest { layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); layer_tree_host()->SetViewportSizeAndScale(viewport_size_, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); client_.set_bounds(root->bounds()); } @@ -8311,8 +8343,7 @@ class LayerTreeHostTestQueueImageDecode : public LayerTreeHostTest { image_ = DrawImage(CreateDiscardablePaintImage(gfx::Size(400, 400)), SkIRect::MakeWH(400, 400), kNone_SkFilterQuality, - SkMatrix::I(), PaintImage::kDefaultFrameIndex, - gfx::ColorSpace()); + SkMatrix::I(), PaintImage::kDefaultFrameIndex); auto callback = base::Bind(&LayerTreeHostTestQueueImageDecode::ImageDecodeFinished, base::Unretained(this)); @@ -8880,17 +8911,22 @@ class LayerTreeHostTestNewLocalSurfaceIdForcesDraw : public LayerTreeHostTest { void BeginTest() override { layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); - local_surface_id_ = allocator_.GenerateId(); - PostSetLocalSurfaceIdToMainThread(local_surface_id_); + allocator_.GenerateId(); + local_surface_id_allocation_ = + allocator_.GetCurrentLocalSurfaceIdAllocation(); + PostSetLocalSurfaceIdAllocationToMainThread(local_surface_id_allocation_); } void DidReceiveCompositorFrameAck() override { switch (layer_tree_host()->SourceFrameNumber()) { case 1: - local_surface_id_ = allocator_.GenerateId(); - PostSetLocalSurfaceIdToMainThread(local_surface_id_); + allocator_.GenerateId(); + local_surface_id_allocation_ = + allocator_.GetCurrentLocalSurfaceIdAllocation(); + PostSetLocalSurfaceIdAllocationToMainThread( + local_surface_id_allocation_); break; case 2: EndTest(); @@ -8901,7 +8937,7 @@ class LayerTreeHostTestNewLocalSurfaceIdForcesDraw : public LayerTreeHostTest { } void AfterTest() override {} - viz::LocalSurfaceId local_surface_id_; + viz::LocalSurfaceIdAllocation local_surface_id_allocation_; viz::ParentLocalSurfaceIdAllocator allocator_; }; @@ -8942,5 +8978,92 @@ class DidReceiveCompositorFrameAckNotSentWhenNotNeeded SINGLE_AND_MULTI_THREAD_TEST_F( DidReceiveCompositorFrameAckNotSentWhenNotNeeded); +// Confirms that requests to force send RFM are forwarded once (and exactly +// once) to the RFM observer. Does this by drawing 3 frames and requesting +// force send from only the second then validating the request. +class LayerTreeHostTestRequestForceSendMetadata + : public LayerTreeHostTest, + public RenderFrameMetadataObserver { + public: + // Provides a wrapper which can be passed to LayerTreeHost, but just forwards + // to the test class. + class ForwardingRenderFrameMetadataObserver + : public RenderFrameMetadataObserver { + public: + explicit ForwardingRenderFrameMetadataObserver( + RenderFrameMetadataObserver* target) + : target_(target) {} + + // RenderFrameMetadataObserver implementation. + void BindToCurrentThread() override { target_->BindToCurrentThread(); } + void OnRenderFrameSubmission( + const RenderFrameMetadata& render_frame_metadata, + viz::CompositorFrameMetadata* compositor_frame_metadata, + bool force_send) override { + target_->OnRenderFrameSubmission(render_frame_metadata, + compositor_frame_metadata, force_send); + } + + private: + RenderFrameMetadataObserver* target_ = nullptr; + }; + + LayerTreeHostTestRequestForceSendMetadata() = default; + + void BeginTest() override { + // Just set up a basic frame which can be repeatedly re-drawn. + layer_tree_host()->SetRenderFrameObserver( + std::make_unique<ForwardingRenderFrameMetadataObserver>(this)); + layer_tree_host()->SetViewportSizeAndScale(gfx::Size(10, 10), 1.f, + viz::LocalSurfaceIdAllocation()); + layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); + + layer_ = FakePictureLayer::Create(&client_); + layer_->SetBounds(gfx::Size(10, 10)); + layer_->SetPosition(gfx::PointF(0.f, 0.f)); + layer_->SetIsDrawable(true); + layer_tree_host()->root_layer()->AddChild(layer_); + + PostSetNeedsCommitToMainThread(); + client_.set_bounds(layer_->bounds()); + } + + void DidCommitAndDrawFrame() override { + // Draw three frames, sending a request to force send metadata on the + // middle (second) frame. + if (num_draw_layers_ == 3) + return; + if (num_draw_layers_ == 2) + layer_tree_host()->RequestForceSendMetadata(); + layer_->SetNeedsDisplay(); + } + + void DrawLayersOnThread(LayerTreeHostImpl* impl) override { + num_draw_layers_++; + if (num_draw_layers_ == 3) + EndTest(); + } + + void AfterTest() override { EXPECT_EQ(1, num_force_sends_); } + + // RenderFrameMetadataObserver implementation. Called on thread. + void BindToCurrentThread() override {} + void OnRenderFrameSubmission( + const RenderFrameMetadata& render_frame_metadata, + viz::CompositorFrameMetadata* compositor_frame_metadata, + bool force_send) override { + if (force_send) + num_force_sends_++; + } + + private: + FakeContentLayerClient client_; + scoped_refptr<Layer> layer_; + int num_draw_layers_ = 0; + int num_force_sends_ = 0; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestForceSendMetadata); + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc index 4f0c551c681..a871ac9d1a9 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_context.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc @@ -818,30 +818,46 @@ class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest { root_->AddChild(child_); child_->AddChild(grandchild_); - layer_tree_host()->SetRootLayer(root_); LayerTreeHostContextTest::SetupTree(); client_.set_bounds(root_->bounds()); } void BeginTest() override { PostSetNeedsCommitToMainThread(); } + void AttachTree() { layer_tree_host()->SetRootLayer(root_); } + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl); + ++num_commits_; + FakePictureLayerImpl* root_picture = nullptr; FakePictureLayerImpl* child_picture = nullptr; FakePictureLayerImpl* grandchild_picture = nullptr; - - root_picture = static_cast<FakePictureLayerImpl*>( - host_impl->active_tree()->root_layer_for_testing()); - child_picture = static_cast<FakePictureLayerImpl*>( - host_impl->active_tree()->LayerById(child_->id())); - grandchild_picture = static_cast<FakePictureLayerImpl*>( - host_impl->active_tree()->LayerById(grandchild_->id())); - - ++num_commits_; + // Root layer isn't attached on first activation so the static_cast will + // fail before second activation. + if (num_commits_ >= 2) { + root_picture = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->root_layer_for_testing()); + child_picture = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->LayerById(child_->id())); + grandchild_picture = static_cast<FakePictureLayerImpl*>( + host_impl->active_tree()->LayerById(grandchild_->id())); + } switch (num_commits_) { case 1: + // Because setting the colorspace on the first activation releases + // resources, don't attach the layers until the first activation. + // Because of single thread vs multi thread differences (i.e. + // commit to active tree), if this delay is not done, then the + // active tree layers will have a different number of resource + // releasing. + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&LayerTreeHostContextTestLayersNotified::AttachTree, + base::Unretained(this))); + break; + case 2: EXPECT_EQ(0u, root_picture->release_resources_count()); EXPECT_EQ(0u, child_picture->release_resources_count()); EXPECT_EQ(0u, grandchild_picture->release_resources_count()); @@ -850,7 +866,7 @@ class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest { LoseContext(); times_to_fail_create_ = 1; break; - case 2: + case 3: EXPECT_TRUE(root_picture->release_resources_count()); EXPECT_TRUE(child_picture->release_resources_count()); EXPECT_TRUE(grandchild_picture->release_resources_count()); @@ -1617,14 +1633,19 @@ class TileResourceFreedIfLostWhileExported : public LayerTreeHostContextTest { void BeginTest() override { PostSetNeedsCommitToMainThread(); } void DrawLayersOnThread(LayerTreeHostImpl* impl) override { + auto* context_provider = static_cast<viz::TestContextProvider*>( + impl->layer_tree_frame_sink()->worker_context_provider()); + viz::TestSharedImageInterface* sii = + context_provider->SharedImageInterface(); switch (impl->active_tree()->source_frame_number()) { case 0: // The PicturLayer has a texture for a tile, that has been exported to // the display compositor now. EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing()); EXPECT_EQ(1u, impl->resource_pool()->resource_count()); - // Shows that the tile texture is allocated with the current context. - num_textures_ = gl_->NumTextures(); + // Shows that the tile texture is allocated with the current worker + // context. + num_textures_ = sii->shared_image_count(); EXPECT_GT(num_textures_, 0u); // Lose the LayerTreeFrameSink connection. The tile resource should @@ -1638,8 +1659,8 @@ class TileResourceFreedIfLostWhileExported : public LayerTreeHostContextTest { EXPECT_EQ(1u, impl->resource_provider()->num_resources_for_testing()); EXPECT_EQ(1u, impl->resource_pool()->resource_count()); // Shows that the replacement tile texture is re-allocated with the - // current context, not just the previous one. - EXPECT_EQ(num_textures_, gl_->NumTextures()); + // current worker context, not just the previous one. + EXPECT_EQ(num_textures_, sii->shared_image_count()); EndTest(); } } @@ -1736,9 +1757,12 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame return; deferred_ = true; - // Defer commits before the BeginFrame completes, causing it to be delayed. - scoped_defer_commits_ = layer_tree_host()->DeferCommits(); - // Meanwhile, lose the context while we are in defer commits. + // TODO(schenney): This should switch back to defer_commits_ because there + // is no way in the real code to start deferring main frame updates when + // inside WillBeginMainFrame. Defer commits before the BeginFrame completes, + // causing it to be delayed. + scoped_defer_main_frame_update_ = layer_tree_host()->DeferMainFrameUpdate(); + // Meanwhile, lose the context while we are in defer BeginMainFrame. ImplThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame:: @@ -1746,8 +1770,8 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame base::Unretained(this))); // After the first frame, we will lose the context and then not start - // allowing commits until that happens. The 2nd frame should not happen - // before DidInitializeLayerTreeFrameSink occurs. + // lifecycle updates and commits until that happens. The 2nd frame should + // not happen before DidInitializeLayerTreeFrameSink occurs. lost_ = true; } @@ -1759,15 +1783,18 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame void LoseContextOnImplThread() { LoseContext(); + // TODO(schenney): This should switch back to defer_commits_ to match the + // change above. // After losing the context, stop deferring commits. - PostReturnDeferCommitsToMainThread(std::move(scoped_defer_commits_)); + PostReturnDeferMainFrameUpdateToMainThread( + std::move(scoped_defer_main_frame_update_)); } void DidCommitAndDrawFrame() override { EndTest(); } void AfterTest() override {} - std::unique_ptr<ScopedDeferCommits> scoped_defer_commits_; + std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; bool deferred_ = false; bool lost_ = true; }; diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc index 83daa78f332..2bc31da1d37 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -7,6 +7,7 @@ #include "base/location.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "cc/layers/effect_tree_layer_list_iterator.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_picture_layer.h" @@ -336,8 +337,8 @@ class LayerTreeHostCopyRequestTestLayerDestroyed EXPECT_EQ(1, callback_count_); // Prevent drawing so we can't make a copy of the impl_destroyed layer. - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); break; case 2: // Flush the message loops and make sure the callbacks run. @@ -736,7 +737,7 @@ class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw // Prevent drawing. layer_tree_host()->SetViewportSizeAndScale(gfx::Size(0, 0), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); AddCopyRequest(copy_layer_.get()); } @@ -751,8 +752,8 @@ class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw void DidCommit() override { if (layer_tree_host()->SourceFrameNumber() == 1) { // Allow drawing. - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(root_->bounds()), - 1.f, viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(root_->bounds()), 1.f, viz::LocalSurfaceIdAllocation()); AddCopyRequest(copy_layer_.get()); } @@ -1097,8 +1098,8 @@ class LayerTreeHostCopyRequestTestDestroyBeforeCopy base::Unretained(this))); copy_layer_->RequestCopyOfOutput(std::move(request)); - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); break; } case 2: @@ -1111,7 +1112,7 @@ class LayerTreeHostCopyRequestTestDestroyBeforeCopy // Allow us to draw now. layer_tree_host()->SetViewportSizeAndScale( layer_tree_host()->root_layer()->bounds(), 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); break; case 4: EXPECT_EQ(1, callback_count_); @@ -1178,8 +1179,8 @@ class LayerTreeHostCopyRequestTestShutdownBeforeCopy base::Unretained(this))); copy_layer_->RequestCopyOfOutput(std::move(request)); - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); break; } case 2: diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc index c84926bc3bc..809985aa5f2 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc @@ -108,8 +108,8 @@ class LayerTreeHostDamageTestSetViewportSizeAndScale void DidCommitAndDrawFrame() override { switch (layer_tree_host()->SourceFrameNumber()) { case 1: - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(15, 15), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(15, 15), 1.f, viz::LocalSurfaceIdAllocation()); break; } } diff --git a/chromium/cc/trees/layer_tree_host_unittest_masks.cc b/chromium/cc/trees/layer_tree_host_unittest_masks.cc index b1615f0eb7e..d0dfd9b9ba7 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_masks.cc @@ -4,6 +4,7 @@ #include "cc/trees/layer_tree_host.h" +#include "base/time/time.h" #include "cc/test/fake_picture_layer.h" #include "cc/test/fake_recording_source.h" #include "cc/test/layer_tree_test.h" @@ -532,8 +533,8 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest { switch (layer_tree_host()->SourceFrameNumber()) { case 1: gfx::Size double_root_size(200, 200); - layer_tree_host()->SetViewportSizeAndScale(double_root_size, 2.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + double_root_size, 2.f, viz::LocalSurfaceIdAllocation()); break; } } diff --git a/chromium/cc/trees/layer_tree_host_unittest_picture.cc b/chromium/cc/trees/layer_tree_host_unittest_picture.cc index 205d1f2c648..7eed6e1c428 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_picture.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_picture.cc @@ -4,6 +4,7 @@ #include "cc/trees/layer_tree_host.h" +#include "base/time/time.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_picture_layer.h" #include "cc/test/fake_picture_layer_impl.h" @@ -192,8 +193,8 @@ class LayerTreeHostPictureTestResizeViewportWithGpuRaster // Change the picture layer's size along with the viewport, so it will // consider picking a new tile size. picture_->SetBounds(gfx::Size(768, 1056)); - layer_tree_host()->SetViewportSizeAndScale(gfx::Size(768, 1056), 1.f, - viz::LocalSurfaceId()); + layer_tree_host()->SetViewportSizeAndScale( + gfx::Size(768, 1056), 1.f, viz::LocalSurfaceIdAllocation()); break; case 2: EndTest(); @@ -599,7 +600,7 @@ class LayerTreeHostPictureTestForceRecalculateScales layer_tree_host()->SetRootLayer(root); layer_tree_host()->SetViewportSizeAndScale(size, 1.f, - viz::LocalSurfaceId()); + viz::LocalSurfaceIdAllocation()); client_.set_fill_with_nonsolid_color(true); client_.set_bounds(size); diff --git a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc index 9d207e792be..b918f70e69a 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc @@ -423,4 +423,123 @@ class LayerTreeHostProxyTestCommitWaitsForActivationMFBA MULTI_THREAD_TEST_F(LayerTreeHostProxyTestCommitWaitsForActivationMFBA); +// Tests that SingleThreadProxy correctly reports pending animations when +// requested from the impl-side. +class LayerTreeHostProxyTestImplFrameCausesAnimatePending + : public LayerTreeHostProxyTest { + protected: + LayerTreeHostProxyTestImplFrameCausesAnimatePending() = default; + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + switch (host_impl->sync_tree()->source_frame_number()) { + case 0: { + EXPECT_FALSE(proxy()->RequestedAnimatePending()); + host_impl->SetNeedsOneBeginImplFrame(); + EXPECT_TRUE(proxy()->RequestedAnimatePending()); + PostSetNeedsCommitToMainThread(); + break; + } + case 1: { + EXPECT_FALSE(proxy()->RequestedAnimatePending()); + EndTest(); + break; + } + default: { NOTREACHED(); } + } + } + + void AfterTest() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(LayerTreeHostProxyTestImplFrameCausesAnimatePending); +}; + +SINGLE_THREAD_TEST_F(LayerTreeHostProxyTestImplFrameCausesAnimatePending); + +// Test that the SingleThreadProxy correctly records and clears commit requests +// from the impl-side. +class LayerTreeHostProxyTestNeedsCommitFromImpl + : public LayerTreeHostProxyTest { + protected: + LayerTreeHostProxyTestNeedsCommitFromImpl() = default; + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + switch (host_impl->sync_tree()->source_frame_number()) { + case 0: { + host_impl->SetNeedsCommit(); + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&LayerTreeHostProxyTestNeedsCommitFromImpl:: + CheckCommitRequested, + base::Unretained(this))); + break; + } + case 1: { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&LayerTreeHostProxyTestNeedsCommitFromImpl:: + CheckRequestClearedAndEnd, + base::Unretained(this))); + break; + } + default: { NOTREACHED(); } + } + } + + void CheckCommitRequested() { EXPECT_TRUE(proxy()->CommitRequested()); } + + void CheckRequestClearedAndEnd() { + EXPECT_FALSE(proxy()->CommitRequested()); + EndTest(); + } + + void AfterTest() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(LayerTreeHostProxyTestNeedsCommitFromImpl); +}; + +SINGLE_THREAD_TEST_F(LayerTreeHostProxyTestNeedsCommitFromImpl); + +// Test that a commit is correctly delayed but is not lost when turning +// invisible, and after turning visible, the commit is executed. +// This is a regression test for https://crbug.com/890008 +class LayerTreeHostProxyTestDelayedCommitDueToVisibility + : public LayerTreeHostProxyTest { + protected: + LayerTreeHostProxyTestDelayedCommitDueToVisibility() = default; + ~LayerTreeHostProxyTestDelayedCommitDueToVisibility() override = default; + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void WillSendBeginMainFrameOnThread(LayerTreeHostImpl*) override { + if (!set_invisible_once_) { + set_invisible_once_ = true; + PostSetVisibleToMainThread(false); + } + } + + void BeginMainFrameAbortedOnThread(LayerTreeHostImpl*, + CommitEarlyOutReason reason) override { + EXPECT_EQ(CommitEarlyOutReason::ABORTED_NOT_VISIBLE, reason); + PostSetVisibleToMainThread(true); + } + + void DidCommit() override { EndTest(); } + + void AfterTest() override {} + + private: + bool set_invisible_once_ = false; + + DISALLOW_COPY_AND_ASSIGN(LayerTreeHostProxyTestDelayedCommitDueToVisibility); +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostProxyTestDelayedCommitDueToVisibility); + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index f3e04c1d449..db91dda80b5 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -20,7 +20,7 @@ #include "base/strings/stringprintf.h" #include "base/timer/elapsed_timer.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" #include "cc/base/math_util.h" @@ -85,6 +85,7 @@ LayerTreeImpl::LayerTreeImpl( page_scale_factor_(page_scale_factor), min_page_scale_factor_(0), max_page_scale_factor_(0), + external_page_scale_factor_(1.f), device_scale_factor_(1.f), painted_device_scale_factor_(1.f), content_source_id_(0), @@ -476,6 +477,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { // tree so only the limits need to be provided. target_tree->PushPageScaleFactorAndLimits(nullptr, min_page_scale_factor(), max_page_scale_factor()); + target_tree->SetExternalPageScaleFactor(external_page_scale_factor_); target_tree->SetRasterColorSpace(raster_color_space_id_, raster_color_space_); target_tree->elastic_overscroll()->PushPendingToActive(); @@ -489,11 +491,15 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { if (TakeNewLocalSurfaceIdRequest()) target_tree->RequestNewLocalSurfaceId(); - target_tree->SetLocalSurfaceIdFromParent(local_surface_id_from_parent()); + target_tree->SetLocalSurfaceIdAllocationFromParent( + local_surface_id_allocation_from_parent()); target_tree->pending_page_scale_animation_ = std::move(pending_page_scale_animation_); + if (TakeForceSendMetadataRequest()) + target_tree->RequestForceSendMetadata(); + target_tree->RegisterSelection(selection_); // This should match the property synchronization in @@ -523,6 +529,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { target_tree->HandleTickmarksVisibilityChange(); target_tree->HandleScrollbarShowRequestsFromMain(); target_tree->AddPresentationCallbacks(std::move(presentation_callbacks_)); + presentation_callbacks_.clear(); } void LayerTreeImpl::HandleTickmarksVisibilityChange() { @@ -610,7 +617,7 @@ LayerImplList::reverse_iterator LayerTreeImpl::rend() { } bool LayerTreeImpl::IsElementInLayerList(ElementId element_id) const { - return elements_in_layer_list_.count(element_id); + return elements_in_property_trees_.count(element_id); } ElementListType LayerTreeImpl::GetElementTypeForAnimation() const { @@ -619,9 +626,6 @@ ElementListType LayerTreeImpl::GetElementTypeForAnimation() const { void LayerTreeImpl::AddToElementLayerList(ElementId element_id, LayerImpl* layer) { - DCHECK(layer); - DCHECK(layer->element_id() == element_id); - if (!element_id) return; @@ -631,17 +635,17 @@ void LayerTreeImpl::AddToElementLayerList(ElementId element_id, #if DCHECK_IS_ON() bool element_id_collision_detected = - elements_in_layer_list_.count(element_id); + elements_in_property_trees_.count(element_id); DCHECK(!element_id_collision_detected); #endif - elements_in_layer_list_.insert(element_id); + elements_in_property_trees_.insert(element_id); host_impl_->mutator_host()->RegisterElement(element_id, GetElementTypeForAnimation()); - if (layer->scrollable()) + if (layer && layer->scrollable()) AddScrollableLayer(layer); } @@ -656,7 +660,7 @@ void LayerTreeImpl::RemoveFromElementLayerList(ElementId element_id) { host_impl_->mutator_host()->UnregisterElement(element_id, GetElementTypeForAnimation()); - elements_in_layer_list_.erase(element_id); + elements_in_property_trees_.erase(element_id); element_id_to_scrollable_layer_.erase(element_id); } @@ -841,8 +845,12 @@ void LayerTreeImpl::UpdateTransformAnimation(ElementId element_id, TransformNode* LayerTreeImpl::PageScaleTransformNode() { auto* page_scale = PageScaleLayer(); - if (!page_scale) - return nullptr; + if (!page_scale) { + // TODO(crbug.com/909750): Check all other callers of PageScaleLayer() and + // switch to viewport_property_ids_.page_scale_transform if needed. + return property_trees()->transform_tree.Node( + viewport_property_ids_.page_scale_transform); + } return property_trees()->transform_tree.Node( page_scale->transform_tree_index()); @@ -857,8 +865,8 @@ void LayerTreeImpl::UpdatePageScaleNode() { // When the page scale layer is also the root layer (this happens in the UI // compositor), the node should also store the combined scale factor and not // just the page scale factor. - // TODO(bokan): Need to implement this behavior for - // BlinkGeneratedPropertyTrees. i.e. (no page scale layer). + // TODO(crbug.com/909750): Implement this behavior without PageScaleLayer, + // e.g. when we switch the UI compositor to create property trees. float device_scale_factor_for_page_scale_layer = 1.f; gfx::Transform device_transform_for_page_scale_layer; if (IsRootLayer(PageScaleLayer())) { @@ -968,6 +976,8 @@ bool LayerTreeImpl::ClampBrowserControlsShownRatio() { } bool LayerTreeImpl::SetCurrentBrowserControlsShownRatio(float ratio) { + TRACE_EVENT1("cc", "LayerTreeImpl::SetCurrentBrowserControlsShownRatio", + "ratio", ratio); bool changed = top_controls_shown_ratio_->SetCurrent(ratio); changed |= ClampBrowserControlsShownRatio(); return changed; @@ -1040,9 +1050,11 @@ void LayerTreeImpl::SetDeviceScaleFactor(float device_scale_factor) { host_impl_->SetNeedUpdateGpuRasterizationStatus(); } -void LayerTreeImpl::SetLocalSurfaceIdFromParent( - const viz::LocalSurfaceId& local_surface_id_from_parent) { - local_surface_id_from_parent_ = local_surface_id_from_parent; +void LayerTreeImpl::SetLocalSurfaceIdAllocationFromParent( + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent) { + local_surface_id_allocation_from_parent_ = + local_surface_id_allocation_from_parent; } void LayerTreeImpl::RequestNewLocalSurfaceId() { @@ -1099,6 +1111,15 @@ void LayerTreeImpl::SetRasterColorSpace( raster_color_space_ = raster_color_space; } +void LayerTreeImpl::SetExternalPageScaleFactor( + float external_page_scale_factor) { + if (external_page_scale_factor_ == external_page_scale_factor) + return; + + external_page_scale_factor_ = external_page_scale_factor; + DidUpdatePageScale(); +} + SyncedProperty<ScaleGroup>* LayerTreeImpl::page_scale_factor() { return page_scale_factor_.get(); } @@ -1383,22 +1404,14 @@ const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const { } gfx::SizeF LayerTreeImpl::ScrollableSize() const { - LayerImpl* root_scroll_layer = nullptr; - LayerImpl* root_container_layer = nullptr; - if (OuterViewportScrollLayer()) { - root_scroll_layer = OuterViewportScrollLayer(); - root_container_layer = OuterViewportContainerLayer(); - } else if (InnerViewportScrollLayer()) { - root_scroll_layer = InnerViewportScrollLayer(); - root_container_layer = InnerViewportContainerLayer(); - } - - if (!root_scroll_layer || !root_container_layer) + auto* scroll_node = OuterViewportScrollNode() ? OuterViewportScrollNode() + : InnerViewportScrollNode(); + if (!scroll_node) return gfx::SizeF(); - - gfx::SizeF content_size = root_scroll_layer->BoundsForScrolling(); - content_size.SetToMax(root_container_layer->BoundsForScrolling()); - return content_size; + const auto& scroll_tree = property_trees()->scroll_tree; + auto size = scroll_tree.scroll_bounds(scroll_node->id); + size.SetToMax(gfx::SizeF(scroll_tree.container_bounds(scroll_node->id))); + return size; } LayerImpl* LayerTreeImpl::LayerById(int id) const { @@ -2309,6 +2322,12 @@ LayerTreeImpl::TakePendingPageScaleAnimation() { return std::move(pending_page_scale_animation_); } +bool LayerTreeImpl::TakeForceSendMetadataRequest() { + bool force_send_metadata_request = force_send_metadata_request_; + force_send_metadata_request_ = false; + return force_send_metadata_request; +} + void LayerTreeImpl::ResetAllChangeTracking() { layers_that_should_push_properties_.clear(); // Iterate over all layers, including masks. diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index f5dd26f151f..a7a3674f440 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -13,6 +13,7 @@ #include "base/containers/flat_set.h" #include "base/macros.h" +#include "base/time/time.h" #include "base/values.h" #include "cc/base/synced_property.h" #include "cc/input/event_listener_properties.h" @@ -180,6 +181,7 @@ class CC_EXPORT LayerTreeImpl { void PushPropertyTreesTo(LayerTreeImpl* tree_impl); void PushPropertiesTo(LayerTreeImpl* tree_impl); void PushSurfaceRangesTo(LayerTreeImpl* tree_impl); + void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl); void MoveChangeTrackingToLayers(); @@ -284,6 +286,11 @@ class CC_EXPORT LayerTreeImpl { const_cast<const LayerTreeImpl*>(this)->OuterViewportScrollNode()); } + void set_viewport_property_ids( + const LayerTreeHost::ViewportPropertyIds& ids) { + viewport_property_ids_ = ids; + } + void ApplySentScrollAndScaleDeltasFromAbortedCommit(); SkColor background_color() const { return background_color_; } @@ -319,9 +326,12 @@ class CC_EXPORT LayerTreeImpl { void set_content_source_id(uint32_t id) { content_source_id_ = id; } uint32_t content_source_id() { return content_source_id_; } - void SetLocalSurfaceIdFromParent(const viz::LocalSurfaceId& id); - const viz::LocalSurfaceId& local_surface_id_from_parent() const { - return local_surface_id_from_parent_; + void SetLocalSurfaceIdAllocationFromParent( + const viz::LocalSurfaceIdAllocation& + local_surface_id_allocation_from_parent); + const viz::LocalSurfaceIdAllocation& local_surface_id_allocation_from_parent() + const { + return local_surface_id_allocation_from_parent_; } void RequestNewLocalSurfaceId(); @@ -344,6 +354,10 @@ class CC_EXPORT LayerTreeImpl { void SetRasterColorSpace(int raster_color_space_id, const gfx::ColorSpace& raster_color_space); + void SetExternalPageScaleFactor(float external_page_scale_factor); + float external_page_scale_factor() const { + return external_page_scale_factor_; + } const gfx::ColorSpace& raster_color_space() const { return raster_color_space_; } @@ -545,6 +559,10 @@ class CC_EXPORT LayerTreeImpl { std::unique_ptr<PendingPageScaleAnimation> pending_animation); std::unique_ptr<PendingPageScaleAnimation> TakePendingPageScaleAnimation(); + // Requests that we force send RenderFrameMetadata with the next frame. + void RequestForceSendMetadata() { force_send_metadata_request_ = true; } + bool TakeForceSendMetadataRequest(); + void DidUpdateScrollOffset(ElementId id); // Mark the scrollbar geometries (e.g., thumb size and position) as needing an @@ -599,6 +617,11 @@ class CC_EXPORT LayerTreeImpl { LayerTreeLifecycle& lifecycle() { return lifecycle_; } + const std::unordered_set<ElementId, ElementIdHash>& + elements_in_property_trees() { + return elements_in_property_trees_; + } + protected: float ClampPageScaleFactorToLimits(float page_scale_factor) const; void PushPageScaleFactorAndLimits(const float* page_scale_factor, @@ -611,6 +634,8 @@ class CC_EXPORT LayerTreeImpl { bool ClampBrowserControlsShownRatio(); private: + friend class LayerTreeHost; + TransformNode* PageScaleTransformNode(); void UpdatePageScaleNode(); @@ -632,12 +657,14 @@ class CC_EXPORT LayerTreeImpl { int last_scrolled_scroll_node_index_; ViewportLayerIds viewport_layer_ids_; + LayerTreeHost::ViewportPropertyIds viewport_property_ids_; LayerSelection selection_; scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; + float external_page_scale_factor_; float device_scale_factor_; float painted_device_scale_factor_; @@ -645,7 +672,7 @@ class CC_EXPORT LayerTreeImpl { gfx::ColorSpace raster_color_space_; uint32_t content_source_id_; - viz::LocalSurfaceId local_surface_id_from_parent_; + viz::LocalSurfaceIdAllocation local_surface_id_allocation_from_parent_; bool new_local_surface_id_request_ = false; gfx::Size device_viewport_size_; @@ -663,7 +690,7 @@ class CC_EXPORT LayerTreeImpl { base::flat_set<LayerImpl*> layers_that_should_push_properties_; // Set of ElementIds which are present in the |layer_list_|. - std::unordered_set<ElementId, ElementIdHash> elements_in_layer_list_; + std::unordered_set<ElementId, ElementIdHash> elements_in_property_trees_; std::unordered_map<ElementId, float, ElementIdHash> element_id_to_opacity_animations_; @@ -735,6 +762,10 @@ class CC_EXPORT LayerTreeImpl { std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation_; + // Whether we have a request to force-send RenderFrameMetadata with the next + // frame. + bool force_send_metadata_request_ = false; + // Tracks the lifecycle which is used for enforcing dependencies between // lifecycle states. See: |LayerTreeLifecycle|. LayerTreeLifecycle lifecycle_; diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc index 9cd9d6ce6af..1c35945d640 100644 --- a/chromium/cc/trees/layer_tree_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_impl_unittest.cc @@ -2276,6 +2276,29 @@ TEST_F(LayerTreeImplTest, HitTestingCorrectLayerWheelListener) { EXPECT_EQ(2, result_layer->id()); } +// When using layer lists, we may not have layers for the outer viewport. This +// test verifies that scroll size can be calculated using property tree nodes. +TEST_F(LayerTreeImplTest, ScrollSizeWithoutLayers) { + const gfx::Size inner_viewport_size(1000, 1000); + const gfx::Size outer_viewport_size(1000, 1000); + const gfx::Size scroll_layer_size(2000, 2000); + + auto* tree_impl = host_impl().active_tree(); + LayerTestCommon::SetupBrowserControlsAndScrollLayerWithVirtualViewport( + &host_impl(), tree_impl, 50, inner_viewport_size, outer_viewport_size, + scroll_layer_size); + + // With viewport layers the scrollable size should be correct. + EXPECT_EQ(gfx::SizeF(scroll_layer_size), tree_impl->ScrollableSize()); + + // The scrollable size should be correct without non-outer viewport layers. + LayerTreeImpl::ViewportLayerIds updated_viewport_ids; + updated_viewport_ids.outer_viewport_scroll = + tree_impl->OuterViewportScrollLayer()->id(); + tree_impl->SetViewportLayersFromIds(updated_viewport_ids); + EXPECT_EQ(gfx::SizeF(scroll_layer_size), tree_impl->ScrollableSize()); +} + namespace { class StubSwapPromise : public SwapPromise, diff --git a/chromium/cc/trees/layer_tree_mutator.cc b/chromium/cc/trees/layer_tree_mutator.cc index 845ed7dc60f..491eec54fa7 100644 --- a/chromium/cc/trees/layer_tree_mutator.cc +++ b/chromium/cc/trees/layer_tree_mutator.cc @@ -12,11 +12,13 @@ AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( WorkletAnimationId worklet_animation_id, std::string name, double current_time, - std::unique_ptr<AnimationOptions> options) + std::unique_ptr<AnimationOptions> options, + int num_effects) : worklet_animation_id(worklet_animation_id), name(name), current_time(current_time), - options(std::move(options)) {} + options(std::move(options)), + num_effects(num_effects) {} AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( AddAndUpdateState&&) = default; AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default; @@ -97,11 +99,10 @@ std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState( AnimationWorkletOutput::AnimationWorkletOutput() = default; AnimationWorkletOutput::~AnimationWorkletOutput() = default; -AnimationWorkletOutput::AnimationState::AnimationState( - WorkletAnimationId id, - base::Optional<base::TimeDelta> time) - : worklet_animation_id(id), local_time(time) {} +AnimationWorkletOutput::AnimationState::AnimationState(WorkletAnimationId id) + : worklet_animation_id(id) {} AnimationWorkletOutput::AnimationState::AnimationState(const AnimationState&) = default; +AnimationWorkletOutput::AnimationState::~AnimationState() = default; } // namespace cc diff --git a/chromium/cc/trees/layer_tree_mutator.h b/chromium/cc/trees/layer_tree_mutator.h index dd702c49458..42cc317740e 100644 --- a/chromium/cc/trees/layer_tree_mutator.h +++ b/chromium/cc/trees/layer_tree_mutator.h @@ -40,11 +40,13 @@ struct CC_EXPORT AnimationWorkletInput { // Worklet animation's current time, from its associated timeline. double current_time; std::unique_ptr<AnimationOptions> options; + int num_effects; AddAndUpdateState(WorkletAnimationId worklet_animation_id, std::string name, double current_time, - std::unique_ptr<AnimationOptions> options); + std::unique_ptr<AnimationOptions> options, + int num_effects); AddAndUpdateState(AddAndUpdateState&&); ~AddAndUpdateState(); @@ -109,16 +111,12 @@ class CC_EXPORT MutatorInputState { struct CC_EXPORT AnimationWorkletOutput { struct CC_EXPORT AnimationState { - AnimationState(WorkletAnimationId, - base::Optional<base::TimeDelta> local_time); + explicit AnimationState(WorkletAnimationId); AnimationState(const AnimationState&); + ~AnimationState(); WorkletAnimationId worklet_animation_id; - // The animator effect's local time. - // TODO(majidvp): This assumes each animator has a single output effect - // which does not hold once we state support group effects. - // http://crbug.com/767043 - base::Optional<base::TimeDelta> local_time; + std::vector<base::Optional<base::TimeDelta>> local_times; }; AnimationWorkletOutput(); diff --git a/chromium/cc/trees/layer_tree_painter.h b/chromium/cc/trees/layer_tree_painter.h new file mode 100644 index 00000000000..f85707460d5 --- /dev/null +++ b/chromium/cc/trees/layer_tree_painter.h @@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_LAYER_TREE_PAINTER_H_ +#define CC_TREES_LAYER_TREE_PAINTER_H_ + +#include "cc/cc_export.h" + +namespace cc { + +class PaintWorkletInput { + public: + virtual ~PaintWorkletInput() {} +}; + +class CC_EXPORT LayerTreePainter { + public: + virtual ~LayerTreePainter() {} + + // TODO(xidachen) add a PaintWorkletPaint function. +}; + +} // namespace cc + +#endif // CC_TREES_LAYER_TREE_PAINTER_H_ diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index 389e25b5eec..7f074dd977e 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -165,6 +165,12 @@ class CC_EXPORT LayerTreeSettings { // DidReceiveCompositorFrameAck, used by the Compositor but not the // LayerTreeView. bool send_compositor_frame_ack = true; + + // When false, scroll deltas accumulated on the impl thread are rounded to + // integer values when sent to Blink on commit. This flag should eventually + // go away and CC should send Blink fractional values: + // https://crbug.com/414283. + bool commit_fractional_scroll_deltas = false; }; } // namespace cc diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc index 906eab95421..3c73e1d45bf 100644 --- a/chromium/cc/trees/occlusion_tracker.cc +++ b/chromium/cc/trees/occlusion_tracker.cc @@ -224,8 +224,8 @@ static void ReduceOcclusionBelowSurface( return; gfx::Rect affected_area_in_target = - contributing_surface->BackgroundFilters().MapRectReverse(target_rect, - SkMatrix::I()); + contributing_surface->BackdropFilters().MapRectReverse(target_rect, + SkMatrix::I()); // Unite target_rect because we only care about positive outsets. affected_area_in_target.Union(target_rect); @@ -288,7 +288,7 @@ void OcclusionTracker::LeaveToRenderTarget( old_surface->draw_transform()); gfx::Rect unoccluded_surface_rect; - if (old_surface->BackgroundFilters().HasFilterThatMovesPixels()) { + if (old_surface->BackdropFilters().HasFilterThatMovesPixels()) { Occlusion surface_occlusion = GetCurrentOcclusionForContributingSurface( old_surface->draw_transform()); unoccluded_surface_rect = @@ -320,7 +320,7 @@ void OcclusionTracker::LeaveToRenderTarget( } } - if (!old_surface->BackgroundFilters().HasFilterThatMovesPixels()) + if (!old_surface->BackdropFilters().HasFilterThatMovesPixels()) return; ReduceOcclusionBelowSurface(old_surface, unoccluded_surface_rect, diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc index 8893f46dc88..0ba135b2fae 100644 --- a/chromium/cc/trees/occlusion_tracker_unittest.cc +++ b/chromium/cc/trees/occlusion_tracker_unittest.cc @@ -1255,10 +1255,10 @@ class OcclusionTrackerTestSurfaceChildOfSurface : public OcclusionTrackerTest { ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestSurfaceChildOfSurface); -class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter +class OcclusionTrackerTestDontOccludePixelsNeededForBackdropFilter : public OcclusionTrackerTest { protected: - explicit OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter( + explicit OcclusionTrackerTestDontOccludePixelsNeededForBackdropFilter( bool opaque_layers) : OcclusionTrackerTest(opaque_layers) {} void RunMyTest() override { @@ -1282,13 +1282,13 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter // Make a 50x50 filtered surface that is adjacent to occluding layers // which are above it in the z-order in various configurations. The // surface is scaled to test that the pixel moving is done in the target - // space, where the background filter is applied. + // space, where the backdrop filter is applied. TestContentLayerImpl* parent = this->CreateRoot( this->identity_matrix, gfx::PointF(), gfx::Size(200, 200)); LayerImpl* filtered_surface = this->CreateDrawingLayer( parent, scale_by_half, gfx::PointF(50.f, 50.f), gfx::Size(100, 100), false); - filtered_surface->test_properties()->background_filters = filters; + filtered_surface->test_properties()->backdrop_filters = filters; gfx::Rect occlusion_rect; switch (i) { case LEFT: @@ -1333,7 +1333,7 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter EXPECT_EQ(occlusion_inside_surface.ToString(), occlusion.occlusion_from_outside_target().ToString()); - // The surface has a background blur, so it needs pixels that are + // The surface has a backdrop blur, so it needs pixels that are // currently considered occluded in order to be drawn. The pixels it // needs should be removed from the occluded area, so that they are drawn // when we get to the parent. @@ -1367,12 +1367,12 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter }; ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter); + OcclusionTrackerTestDontOccludePixelsNeededForBackdropFilter); -class OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter +class OcclusionTrackerTestPixelsNeededForDropShadowBackdropFilter : public OcclusionTrackerTest { protected: - explicit OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter( + explicit OcclusionTrackerTestPixelsNeededForDropShadowBackdropFilter( bool opaque_layers) : OcclusionTrackerTest(opaque_layers) {} void RunMyTest() override { @@ -1397,13 +1397,13 @@ class OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter // Make a 50x50 filtered surface that is adjacent to occluding layers // which are above it in the z-order in various configurations. The // surface is scaled to test that the pixel moving is done in the target - // space, where the background filter is applied. + // space, where the backdrop filter is applied. TestContentLayerImpl* parent = this->CreateRoot( this->identity_matrix, gfx::PointF(), gfx::Size(200, 200)); LayerImpl* filtered_surface = this->CreateDrawingLayer( parent, scale_by_half, gfx::PointF(50.f, 50.f), gfx::Size(100, 100), false); - filtered_surface->test_properties()->background_filters = filters; + filtered_surface->test_properties()->backdrop_filters = filters; gfx::Rect occlusion_rect; switch (i) { case LEFT: @@ -1448,7 +1448,7 @@ class OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter EXPECT_EQ(occlusion_inside_surface.ToString(), occlusion.occlusion_from_outside_target().ToString()); - // The surface has a background filter, so it needs pixels that are + // The surface has a backdrop filter, so it needs pixels that are // currently considered occluded in order to be drawn. The pixels it // needs should be removed from the occluded area, so that they are drawn // when we get to the parent. @@ -1459,7 +1459,7 @@ class OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter switch (i) { case LEFT: // The right half of the occlusion is close enough to cast a shadow - // that would be visible in the background filter. The shadow reaches + // that would be visible in the backdrop filter. The shadow reaches // 3*5 + 10 = 25 pixels to the right. expected_occlusion = gfx::Rect(0, 0, 25, 200); break; @@ -1488,12 +1488,12 @@ class OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter }; ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestPixelsNeededForDropShadowBackgroundFilter); + OcclusionTrackerTestPixelsNeededForDropShadowBackdropFilter); -class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice +class OcclusionTrackerTestTwoBackdropFiltersReduceOcclusionTwice : public OcclusionTrackerTest { protected: - explicit OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice( + explicit OcclusionTrackerTestTwoBackdropFiltersReduceOcclusionTwice( bool opaque_layers) : OcclusionTrackerTest(opaque_layers) {} void RunMyTest() override { @@ -1520,8 +1520,8 @@ class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice filtered_surface2->test_properties()->force_render_surface = true; FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(1.f)); - filtered_surface1->test_properties()->background_filters = filters; - filtered_surface2->test_properties()->background_filters = filters; + filtered_surface1->test_properties()->backdrop_filters = filters; + filtered_surface2->test_properties()->backdrop_filters = filters; this->CalcDrawEtc(root); @@ -1554,12 +1554,12 @@ class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice }; ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice); + OcclusionTrackerTestTwoBackdropFiltersReduceOcclusionTwice); -class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter +class OcclusionTrackerTestDontReduceOcclusionBelowBackdropFilter : public OcclusionTrackerTest { protected: - explicit OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter( + explicit OcclusionTrackerTestDontReduceOcclusionBelowBackdropFilter( bool opaque_layers) : OcclusionTrackerTest(opaque_layers) {} void RunMyTest() override { @@ -1568,7 +1568,7 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter // Make a 50x50 surface, with a smaller 30x30 layer centered below it. // The surface is scaled to test that the pixel moving is done in the target - // space, where the background filter is applied, and the surface appears at + // space, where the backdrop filter is applied, and the surface appears at // 50, 50. TestContentLayerImpl* parent = this->CreateRoot( this->identity_matrix, gfx::PointF(), gfx::Size(300, 150)); @@ -1583,13 +1583,13 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter filtered_surface->test_properties()->force_render_surface = true; FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(3.f)); - filtered_surface->test_properties()->background_filters = filters; + filtered_surface->test_properties()->backdrop_filters = filters; this->CalcDrawEtc(parent); TestOcclusionTrackerWithClip occlusion(gfx::Rect(0, 0, 1000, 1000)); - // The surface has a background blur, so it blurs non-opaque pixels below + // The surface has a backdrop blur, so it blurs non-opaque pixels below // it. this->VisitLayer(filtered_surface, &occlusion); this->VisitContributingSurface(filtered_surface, &occlusion); @@ -1616,12 +1616,12 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter }; ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter); + OcclusionTrackerTestDontReduceOcclusionBelowBackdropFilter); -class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded +class OcclusionTrackerTestDontReduceOcclusionIfBackdropFilterIsOccluded : public OcclusionTrackerTest { protected: - explicit OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded( + explicit OcclusionTrackerTestDontReduceOcclusionIfBackdropFilterIsOccluded( bool opaque_layers) : OcclusionTrackerTest(opaque_layers) {} void RunMyTest() override { @@ -1631,7 +1631,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded // Make a 50x50 filtered surface that is completely occluded by an opaque // layer which is above it in the z-order. The surface is // scaled to test that the pixel moving is done in the target space, where - // the background filter is applied, and the surface appears at 50, 50. + // the backdrop filter is applied, and the surface appears at 50, 50. TestContentLayerImpl* parent = this->CreateRoot( this->identity_matrix, gfx::PointF(), gfx::Size(200, 150)); LayerImpl* filtered_surface = @@ -1645,7 +1645,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded filtered_surface->test_properties()->force_render_surface = true; FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(3.f)); - filtered_surface->test_properties()->background_filters = filters; + filtered_surface->test_properties()->backdrop_filters = filters; this->CalcDrawEtc(parent); @@ -1664,7 +1664,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded occlusion.occlusion_from_outside_target().ToString()); } - // The surface has a background blur, so it blurs non-opaque pixels below + // The surface has a backdrop blur, so it blurs non-opaque pixels below // it. this->VisitContributingSurface(filtered_surface, &occlusion); { @@ -1681,7 +1681,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded }; ALL_OCCLUSIONTRACKER_TEST( - OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded); + OcclusionTrackerTestDontReduceOcclusionIfBackdropFilterIsOccluded); class OcclusionTrackerTestReduceOcclusionWhenBkgdFilterIsPartiallyOccluded : public OcclusionTrackerTest { @@ -1695,7 +1695,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBkgdFilterIsPartiallyOccluded // Make a 50x50 surface which is partially occluded by opaque layers which // are above it in the z-order. The surface is scaled to test that the - // pixel moving is done in the target space, where the background filter is + // pixel moving is done in the target space, where the backdrop filter is // applied, but the surface appears at 50, 50. TestContentLayerImpl* parent = this->CreateRoot( this->identity_matrix, gfx::PointF(), gfx::Size(300, 150)); @@ -1713,7 +1713,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBkgdFilterIsPartiallyOccluded filtered_surface->test_properties()->force_render_surface = true; FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(3.f)); - filtered_surface->test_properties()->background_filters = filters; + filtered_surface->test_properties()->backdrop_filters = filters; this->CalcDrawEtc(parent); @@ -1722,7 +1722,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBkgdFilterIsPartiallyOccluded this->VisitLayer(beside_surface_layer, &occlusion); this->VisitLayer(above_surface_layer, &occlusion); - // The surface has a background blur, so it blurs non-opaque pixels below + // The surface has a backdrop blur, so it blurs non-opaque pixels below // it. this->VisitLayer(filtered_surface, &occlusion); this->VisitContributingSurface(filtered_surface, &occlusion); diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc index c4fa5bc4a19..b3fff07a268 100644 --- a/chromium/cc/trees/property_tree.cc +++ b/chromium/cc/trees/property_tree.cc @@ -10,7 +10,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/numerics/checked_math.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/layers/layer_impl.h" #include "cc/trees/clip_node.h" #include "cc/trees/effect_node.h" @@ -784,7 +784,7 @@ void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) { // Exceptions: // 1) Nodes that contribute to copy requests, whether hidden or not, must be // drawn. - // 2) Nodes that have a background filter. + // 2) Nodes that have a backdrop filter. // 3) Nodes with animating screen space opacity on main thread or pending tree // are drawn if their parent is drawn irrespective of their opacity. if (node->has_copy_request || node->cache_render_surface) @@ -792,7 +792,7 @@ void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) { else if (EffectiveOpacity(node) == 0.f && (!node->has_potential_opacity_animation || property_trees()->is_active) && - node->background_filters.IsEmpty()) + node->backdrop_filters.IsEmpty()) node->is_drawn = false; else if (parent_node) node->is_drawn = parent_node->is_drawn; @@ -1305,14 +1305,7 @@ void ScrollTree::clear() { gfx::ScrollOffset ScrollTree::MaxScrollOffset(int scroll_node_id) const { const ScrollNode* scroll_node = Node(scroll_node_id); - gfx::SizeF scroll_bounds = - gfx::SizeF(scroll_node->bounds.width(), scroll_node->bounds.height()); - - if (scroll_node->scrolls_inner_viewport) { - scroll_bounds.Enlarge( - property_trees()->inner_viewport_scroll_bounds_delta().x(), - property_trees()->inner_viewport_scroll_bounds_delta().y()); - } + gfx::SizeF scroll_bounds = this->scroll_bounds(scroll_node_id); if (!scroll_node->scrollable || scroll_bounds.IsEmpty()) return gfx::ScrollOffset(); @@ -1337,6 +1330,16 @@ gfx::ScrollOffset ScrollTree::MaxScrollOffset(int scroll_node_id) const { return max_offset; } +gfx::SizeF ScrollTree::scroll_bounds(int scroll_node_id) const { + const ScrollNode* scroll_node = Node(scroll_node_id); + gfx::SizeF bounds(scroll_node->bounds); + if (scroll_node->scrolls_inner_viewport) { + const auto& delta = property_trees()->inner_viewport_scroll_bounds_delta(); + bounds.Enlarge(delta.x(), delta.y()); + } + return bounds; +} + void ScrollTree::OnScrollOffsetAnimated(ElementId id, int scroll_tree_index, const gfx::ScrollOffset& scroll_offset, @@ -1472,10 +1475,17 @@ const gfx::ScrollOffset ScrollTree::GetPixelSnappedScrollOffset( } gfx::ScrollOffset ScrollTree::PullDeltaForMainThread( - SyncedScrollOffset* scroll_offset) { + SyncedScrollOffset* scroll_offset, + bool use_fractional_deltas) { DCHECK(property_trees()->is_active); + + // Once this setting is enabled, all the complicated rounding logic below can + // go away. + if (use_fractional_deltas) + return scroll_offset->PullDeltaForMainThread(); + // TODO(flackr): We should pass the fractional scroll deltas when Blink fully - // supports fractional scrolls. + // supports fractional scrolls. crbug.com/414283. // TODO(flackr): We should ideally round the fractional scrolls in the same // direction as the scroll will be snapped but for common cases this is // equivalent to rounding to the nearest integer offset. @@ -1495,26 +1505,25 @@ gfx::ScrollOffset ScrollTree::PullDeltaForMainThread( return delta; } -void ScrollTree::CollectScrollDeltas( - ScrollAndScaleSet* scroll_info, - ElementId inner_viewport_scroll_element_id) { +void ScrollTree::CollectScrollDeltas(ScrollAndScaleSet* scroll_info, + ElementId inner_viewport_scroll_element_id, + bool use_fractional_deltas) { DCHECK(!property_trees()->is_main_thread); for (auto map_entry : synced_scroll_offset_map_) { gfx::ScrollOffset scroll_delta = - PullDeltaForMainThread(map_entry.second.get()); + PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas); - gfx::Vector2d scroll_delta_vector(scroll_delta.x(), scroll_delta.y()); ElementId id = map_entry.first; if (!scroll_delta.IsZero()) { if (id == inner_viewport_scroll_element_id) { // Inner (visual) viewport is stored separately. scroll_info->inner_viewport_scroll.element_id = id; - scroll_info->inner_viewport_scroll.scroll_delta = scroll_delta_vector; + scroll_info->inner_viewport_scroll.scroll_delta = scroll_delta; } else { LayerTreeHostCommon::ScrollUpdateInfo scroll; scroll.element_id = id; - scroll.scroll_delta = scroll_delta_vector; + scroll.scroll_delta = scroll_delta; scroll_info->scrolls.push_back(scroll); } } @@ -1522,8 +1531,11 @@ void ScrollTree::CollectScrollDeltas( } void ScrollTree::CollectScrollDeltasForTesting() { + LayerTreeSettings settings; + bool use_fractional_deltas = settings.commit_fractional_scroll_deltas; + for (auto map_entry : synced_scroll_offset_map_) { - PullDeltaForMainThread(map_entry.second.get()); + PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas); } } diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h index 85abe4979ad..89118ace357 100644 --- a/chromium/cc/trees/property_tree.h +++ b/chromium/cc/trees/property_tree.h @@ -406,6 +406,7 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { const gfx::ScrollOffset& scroll_offset, LayerTreeImpl* layer_tree_impl); gfx::Size container_bounds(int scroll_node_id) const; + gfx::SizeF scroll_bounds(int scroll_node_id) const; ScrollNode* CurrentlyScrollingNode(); const ScrollNode* CurrentlyScrollingNode() const; #if DCHECK_IS_ON() @@ -437,7 +438,8 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { // reported to the main thread during the main frame. As such, should only be // called on the impl thread side PropertyTrees. void CollectScrollDeltas(ScrollAndScaleSet* scroll_info, - ElementId inner_viewport_scroll_element_id); + ElementId inner_viewport_scroll_element_id, + bool use_fractional_deltas); // Applies deltas sent in the previous main frame onto the impl thread state. // Should only be called on the impl thread side PropertyTrees. @@ -500,7 +502,8 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { SyncedScrollOffsetMap synced_scroll_offset_map_; SyncedScrollOffset* GetOrCreateSyncedScrollOffset(ElementId id); - gfx::ScrollOffset PullDeltaForMainThread(SyncedScrollOffset* scroll_offset); + gfx::ScrollOffset PullDeltaForMainThread(SyncedScrollOffset* scroll_offset, + bool use_fractional_deltas); }; struct AnimationScaleData { diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc index fd6c3edb5f6..674b121c370 100644 --- a/chromium/cc/trees/property_tree_builder.cc +++ b/chromium/cc/trees/property_tree_builder.cc @@ -740,12 +740,12 @@ static inline const gfx::PointF FiltersOrigin(LayerImpl* layer) { return layer->test_properties()->filters_origin; } -static inline const FilterOperations& BackgroundFilters(Layer* layer) { - return layer->background_filters(); +static inline const FilterOperations& BackdropFilters(Layer* layer) { + return layer->backdrop_filters(); } -static inline const FilterOperations& BackgroundFilters(LayerImpl* layer) { - return layer->test_properties()->background_filters; +static inline const FilterOperations& BackdropFilters(LayerImpl* layer) { + return layer->test_properties()->backdrop_filters; } static inline float BackdropFilterQuality(Layer* layer) { @@ -802,7 +802,7 @@ bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, } // If the layer uses a CSS filter. - if (!Filters(layer).IsEmpty() || !BackgroundFilters(layer).IsEmpty()) { + if (!Filters(layer).IsEmpty() || !BackdropFilters(layer).IsEmpty()) { return true; } @@ -991,7 +991,7 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( node->cache_render_surface = CacheRenderSurface(layer); node->has_copy_request = HasCopyRequest(layer); node->filters = Filters(layer); - node->background_filters = BackgroundFilters(layer); + node->backdrop_filters = BackdropFilters(layer); node->backdrop_filter_quality = BackdropFilterQuality(layer); node->filters_origin = FiltersOrigin(layer); node->trilinear_filtering = TrilinearFiltering(layer); diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h index 42d4fd2975c..b9bb0318420 100644 --- a/chromium/cc/trees/proxy.h +++ b/chromium/cc/trees/proxy.h @@ -36,6 +36,9 @@ class CC_EXPORT Proxy { virtual ~Proxy() {} virtual bool IsStarted() const = 0; + + // This function retruns true if the commits go directly to active tree by + // skipping commit to pending tree. virtual bool CommitToActiveTree() const = 0; virtual void SetLayerTreeFrameSink( @@ -56,9 +59,9 @@ class CC_EXPORT Proxy { virtual void NotifyInputThrottledUntilCommit() = 0; - // Defers commits until it is reset. It is only supported when using a - // scheduler. - virtual void SetDeferCommits(bool defer_commits) = 0; + // Defers LayerTreeHost::BeginMainFrameUpdate and commits until it is + // reset. It is only supported when using a scheduler. + virtual void SetDeferMainFrameUpdate(bool defer_main_frame_update) = 0; virtual bool CommitRequested() const = 0; diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc index 6aff668ee58..d3fc4b7ab4b 100644 --- a/chromium/cc/trees/proxy_impl.cc +++ b/chromium/cc/trees/proxy_impl.cc @@ -11,7 +11,7 @@ #include "base/auto_reset.h" #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/devtools_instrumentation.h" #include "cc/benchmarks/benchmark_instrumentation.h" #include "cc/input/browser_controls_offset_manager.h" @@ -40,13 +40,22 @@ unsigned int nextBeginFrameId = 0; } // namespace +// Ensures that a CompletionEvent is always signaled. +class ScopedCompletionEvent { + public: + explicit ScopedCompletionEvent(CompletionEvent* event) : event_(event) {} + ~ScopedCompletionEvent() { event_->Signal(); } + + private: + CompletionEvent* const event_; + DISALLOW_COPY_AND_ASSIGN(ScopedCompletionEvent); +}; + ProxyImpl::ProxyImpl(base::WeakPtr<ProxyMain> proxy_main_weak_ptr, LayerTreeHost* layer_tree_host, TaskRunnerProvider* task_runner_provider) : layer_tree_host_id_(layer_tree_host->GetId()), commit_completion_waits_for_activation_(false), - commit_completion_event_(nullptr), - activation_completion_event_(nullptr), next_frame_is_newly_committed_frame_(false), inside_draw_(false), input_throttled_until_commit_(false), @@ -154,9 +163,10 @@ void ProxyImpl::SetInputThrottledUntilCommitOnImpl(bool is_throttled) { RenewTreePriority(); } -void ProxyImpl::SetDeferCommitsOnImpl(bool defer_commits) const { +void ProxyImpl::SetDeferMainFrameUpdateOnImpl( + bool defer_main_frame_update) const { DCHECK(IsImplThread()); - scheduler_->SetDeferCommits(defer_commits); + scheduler_->SetDeferMainFrameUpdate(defer_main_frame_update); } void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { @@ -260,7 +270,8 @@ void ProxyImpl::NotifyReadyToCommitOnImpl( host_impl_->ReadyToCommit(); - commit_completion_event_ = completion; + commit_completion_event_ = + std::make_unique<ScopedCompletionEvent>(completion); commit_completion_waits_for_activation_ = hold_commit_for_activation; DCHECK(!blocked_main_commit().layer_tree_host); @@ -439,7 +450,6 @@ void ProxyImpl::DidActivateSyncTree() { if (activation_completion_event_) { TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD); - activation_completion_event_->Signal(); activation_completion_event_ = nullptr; } } @@ -503,6 +513,11 @@ void ProxyImpl::DidNotProduceFrame(const viz::BeginFrameAck& ack) { host_impl_->DidNotProduceFrame(ack); } +void ProxyImpl::WillNotReceiveBeginFrame() { + DCHECK(IsImplThread()); + host_impl_->DidNotNeedBeginFrame(); +} + void ProxyImpl::ScheduledActionSendBeginMainFrame( const viz::BeginFrameArgs& args) { DCHECK(IsImplThread()); @@ -518,6 +533,7 @@ void ProxyImpl::ScheduledActionSendBeginMainFrame( host_impl_->EvictedUIResourcesExist(); begin_main_frame_state->completed_image_decode_requests = host_impl_->TakeCompletedImageDecodeRequests(); + host_impl_->WillSendBeginMainFrame(); MainThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_, @@ -572,9 +588,7 @@ void ProxyImpl::ScheduledActionCommit() { // already activated if there was no work to be done. TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD); commit_completion_waits_for_activation_ = false; - activation_completion_event_ = commit_completion_event_; - } else { - commit_completion_event_->Signal(); + activation_completion_event_ = std::move(commit_completion_event_); } commit_completion_event_ = nullptr; diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h index 4bfbf73cd40..038d3752605 100644 --- a/chromium/cc/trees/proxy_impl.h +++ b/chromium/cc/trees/proxy_impl.h @@ -20,6 +20,8 @@ class LayerTreeHost; class ProxyMain; class RenderFrameMetadataObserver; +class ScopedCompletionEvent; + // This class aggregates all the interactions that the main side of the // compositor needs to have with the impl side. // The class is created and lives on the impl thread. @@ -39,7 +41,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr); void InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator); void SetInputThrottledUntilCommitOnImpl(bool is_throttled); - void SetDeferCommitsOnImpl(bool defer_commits) const; + void SetDeferMainFrameUpdateOnImpl(bool defer_main_frame_update) const; void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect); void SetNeedsCommitOnImpl(); void BeginMainFrameAbortedOnImpl( @@ -109,6 +111,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override; void DidFinishImplFrame() override; void DidNotProduceFrame(const viz::BeginFrameAck& ack) override; + void WillNotReceiveBeginFrame() override; void ScheduledActionSendBeginMainFrame( const viz::BeginFrameArgs& args) override; DrawResult ScheduledActionDrawIfPossible() override; @@ -122,6 +125,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, void SendBeginMainFrameNotExpectedSoon() override; void ScheduledActionBeginMainFrameNotExpectedUntil( base::TimeTicks time) override; + void FrameIntervalUpdated(base::TimeDelta interval) override {} size_t CompositedAnimationsCount() const override; size_t MainThreadAnimationsCount() const override; bool CurrentFrameHadRAF() const override; @@ -141,10 +145,10 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, bool commit_completion_waits_for_activation_; // Set when the main thread is waiting on a commit to complete. - CompletionEvent* commit_completion_event_; + std::unique_ptr<ScopedCompletionEvent> commit_completion_event_; // Set when the main thread is waiting for activation to complete. - CompletionEvent* activation_completion_event_; + std::unique_ptr<ScopedCompletionEvent> activation_completion_event_; // Set when the next draw should post DidCommitAndDrawFrame to the main // thread. diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc index c89bd779b18..9bee3eff2c2 100644 --- a/chromium/cc/trees/proxy_main.cc +++ b/chromium/cc/trees/proxy_main.cc @@ -8,7 +8,7 @@ #include <string> #include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" +#include "base/trace_event/traced_value.h" #include "cc/base/completion_event.h" #include "cc/base/devtools_instrumentation.h" #include "cc/benchmarks/benchmark_instrumentation.h" @@ -36,7 +36,7 @@ ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host, deferred_final_pipeline_stage_(NO_PIPELINE_STAGE), commit_waits_for_activation_(false), started_(false), - defer_commits_(false), + defer_main_frame_update_(false), frame_sink_bound_weak_factory_(this), weak_factory_(this) { TRACE_EVENT0("cc", "ProxyMain::ProxyMain"); @@ -138,10 +138,26 @@ void ProxyMain::BeginMainFrame( layer_tree_host_->GetSwapPromiseManager()); // We need to issue image decode callbacks whether or not we will abort this - // commit, since the request ids are only stored in |begin_main_frame_state|. + // update and commit, since the request ids are only stored in + // |begin_main_frame_state|. layer_tree_host_->ImageDecodesFinished( std::move(begin_main_frame_state->completed_image_decode_requests)); + // Visibility check needs to happen before setting + // max_requested_pipeline_stage_. Otherwise a requested commit could get lost + // after tab becomes visible again. + if (!layer_tree_host_->IsVisible()) { + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); + std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises; + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl, + base::Unretained(proxy_impl_.get()), + CommitEarlyOutReason::ABORTED_NOT_VISIBLE, + begin_main_frame_start_time, + base::Passed(&empty_swap_promises))); + return; + } + final_pipeline_stage_ = max_requested_pipeline_stage_; max_requested_pipeline_stage_ = NO_PIPELINE_STAGE; @@ -150,8 +166,8 @@ void ProxyMain::BeginMainFrame( // have side effects on page loading behavior. bool skip_commit = begin_main_frame_state->begin_frame_args.animate_only; - // If commits are deferred, skip the entire pipeline. - bool skip_full_pipeline = defer_commits_; + // If main frame updates and commits are deferred, skip the entire pipeline. + bool skip_full_pipeline = defer_main_frame_update_; // We may have previously skipped paint and commit. If we should still skip it // now, and there was no intermediate request for a commit since the last @@ -180,18 +196,6 @@ void ProxyMain::BeginMainFrame( std::max(final_pipeline_stage_, deferred_final_pipeline_stage_); deferred_final_pipeline_stage_ = NO_PIPELINE_STAGE; - if (!layer_tree_host_->IsVisible()) { - TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); - std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises; - ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl, - base::Unretained(proxy_impl_.get()), - CommitEarlyOutReason::ABORTED_NOT_VISIBLE, - begin_main_frame_start_time, - base::Passed(&empty_swap_promises))); - return; - } - current_pipeline_stage_ = ANIMATE_PIPELINE_STAGE; // Synchronizes scroll offsets and page scale deltas (for pinch zoom) from the @@ -219,11 +223,15 @@ void ProxyMain::BeginMainFrame( // See LayerTreeHostClient::MainFrameUpdate for more documentation on // what this does. - layer_tree_host_->RequestMainFrameUpdate(); + layer_tree_host_->RequestMainFrameUpdate( + true /* record_main_frame_metrics */); + // TODO(schenney) This will be changed to defer_commits_ when we introduce + // the separation between deferring of main frame updates and deferring of + // commits. // At this point the main frame may have deferred commits to avoid committing // right now. - skip_commit |= defer_commits_; + skip_commit |= defer_main_frame_update_; if (skip_commit) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame", @@ -429,21 +437,21 @@ void ProxyMain::NotifyInputThrottledUntilCommit() { base::Unretained(proxy_impl_.get()), true)); } -void ProxyMain::SetDeferCommits(bool defer_commits) { +void ProxyMain::SetDeferMainFrameUpdate(bool defer_main_frame_update) { DCHECK(IsMainThread()); - if (defer_commits_ == defer_commits) + if (defer_main_frame_update_ == defer_main_frame_update) return; - defer_commits_ = defer_commits; - if (defer_commits_) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferCommits", this); + defer_main_frame_update_ = defer_main_frame_update; + if (defer_main_frame_update_) + TRACE_EVENT_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferMainFrameUpdate", this); else - TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferCommits", this); + TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferMainFrameUpdate", this); ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&ProxyImpl::SetDeferCommitsOnImpl, - base::Unretained(proxy_impl_.get()), defer_commits)); + FROM_HERE, base::BindOnce(&ProxyImpl::SetDeferMainFrameUpdateOnImpl, + base::Unretained(proxy_impl_.get()), + defer_main_frame_update)); } bool ProxyMain::CommitRequested() const { diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h index 9e32ce2d311..0005a6e1bfe 100644 --- a/chromium/cc/trees/proxy_main.h +++ b/chromium/cc/trees/proxy_main.h @@ -81,7 +81,7 @@ class CC_EXPORT ProxyMain : public Proxy { void SetNextCommitWaitsForActivation() override; bool RequestedAnimatePending() override; void NotifyInputThrottledUntilCommit() override; - void SetDeferCommits(bool defer_commits) override; + void SetDeferMainFrameUpdate(bool defer_main_frame_update) override; bool CommitRequested() const override; void Start() override; void Stop() override; @@ -134,7 +134,7 @@ class CC_EXPORT ProxyMain : public Proxy { // stopped using Proxy::Stop(). bool started_; - bool defer_commits_; + bool defer_main_frame_update_; // ProxyImpl is created and destroyed on the impl thread, and should only be // accessed on the impl thread. diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc index 304b451b2c3..b666e9c6633 100644 --- a/chromium/cc/trees/render_frame_metadata.cc +++ b/chromium/cc/trees/render_frame_metadata.cc @@ -32,6 +32,7 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const { device_scale_factor == other.device_scale_factor && viewport_size_in_pixels == other.viewport_size_in_pixels && page_scale_factor == other.page_scale_factor && + 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 && #if defined(OS_ANDROID) @@ -44,7 +45,7 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const { root_layer_size == other.root_layer_size && has_transparent_background == other.has_transparent_background && #endif - local_surface_id == other.local_surface_id; + local_surface_id_allocation == other.local_surface_id_allocation; } bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) const { diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h index 8b6c45da6c4..400eeaefe0d 100644 --- a/chromium/cc/trees/render_frame_metadata.h +++ b/chromium/cc/trees/render_frame_metadata.h @@ -6,10 +6,11 @@ #define CC_TREES_RENDER_FRAME_METADATA_H_ #include "base/optional.h" +#include "base/time/time.h" #include "build/build_config.h" #include "cc/cc_export.h" #include "components/viz/common/quads/selection.h" -#include "components/viz/common/surfaces/local_surface_id.h" +#include "components/viz/common/surfaces/local_surface_id_allocation.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" @@ -61,10 +62,13 @@ class CC_EXPORT RenderFrameMetadata { // the size of the root render pass. gfx::Size viewport_size_in_pixels; - // The last viz::LocalSurfaceId used to submit a CompositorFrame. - base::Optional<viz::LocalSurfaceId> local_surface_id; + // The last viz::LocalSurfaceIdAllocation used to submit a CompositorFrame. + base::Optional<viz::LocalSurfaceIdAllocation> local_surface_id_allocation; + // Page scale factor (always 1.f for sub-frame renderers). float page_scale_factor = 1.f; + // Used for testing propagation of page scale factor to sub-frame renderers. + float external_page_scale_factor = 1.f; // Used to position the location top bar and page content, whose precise // position is computed by the renderer compositor. diff --git a/chromium/cc/trees/render_frame_metadata_observer.h b/chromium/cc/trees/render_frame_metadata_observer.h index 69037c5ef5b..13b0263c5c4 100644 --- a/chromium/cc/trees/render_frame_metadata_observer.h +++ b/chromium/cc/trees/render_frame_metadata_observer.h @@ -32,7 +32,8 @@ class CC_EXPORT RenderFrameMetadataObserver { // the display compositor. virtual void OnRenderFrameSubmission( const RenderFrameMetadata& render_frame_metadata, - viz::CompositorFrameMetadata* compositor_frame_metadata) = 0; + viz::CompositorFrameMetadata* compositor_frame_metadata, + bool force_send) = 0; private: DISALLOW_COPY_AND_ASSIGN(RenderFrameMetadataObserver); diff --git a/chromium/cc/trees/scroll_node.cc b/chromium/cc/trees/scroll_node.cc index 9a19d4b4b57..069c731ae98 100644 --- a/chromium/cc/trees/scroll_node.cc +++ b/chromium/cc/trees/scroll_node.cc @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/trace_event/trace_event_argument.h" +#include "cc/trees/scroll_node.h" + #include "cc/base/math_util.h" #include "cc/input/main_thread_scrolling_reason.h" #include "cc/layers/layer.h" #include "cc/trees/element_id.h" #include "cc/trees/property_tree.h" -#include "cc/trees/scroll_node.h" + +#include "base/trace_event/traced_value.h" namespace cc { diff --git a/chromium/cc/trees/scroll_node.h b/chromium/cc/trees/scroll_node.h index b96b696e1b3..de9f9343c8d 100644 --- a/chromium/cc/trees/scroll_node.h +++ b/chromium/cc/trees/scroll_node.h @@ -10,6 +10,7 @@ #include "cc/input/overscroll_behavior.h" #include "cc/input/scroll_snap_data.h" #include "cc/paint/filter_operations.h" +#include "cc/trees/element_id.h" #include "ui/gfx/geometry/size.h" namespace base { diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index 8e79bbbb4fb..2e3b7c613c1 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -9,6 +9,7 @@ #include "base/trace_event/trace_event.h" #include "cc/base/devtools_instrumentation.h" #include "cc/benchmarks/benchmark_instrumentation.h" +#include "cc/input/browser_controls_offset_manager.h" #include "cc/resources/ui_resource_manager.h" #include "cc/scheduler/commit_earlyout_reason.h" #include "cc/scheduler/compositor_timing_history.h" @@ -46,10 +47,11 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host, inside_impl_frame_(false), #endif inside_draw_(false), - defer_commits_(false), + defer_main_frame_update_(false), animate_requested_(false), commit_requested_(false), inside_synchronous_composite_(false), + needs_impl_frame_(false), layer_tree_frame_sink_creation_requested_(false), layer_tree_frame_sink_lost_(true), frame_sink_bound_weak_factory_(this), @@ -258,24 +260,26 @@ void SingleThreadProxy::SetNextCommitWaitsForActivation() { } bool SingleThreadProxy::RequestedAnimatePending() { - return animate_requested_ || commit_requested_; + return animate_requested_ || commit_requested_ || needs_impl_frame_; } -void SingleThreadProxy::SetDeferCommits(bool defer_commits) { +void SingleThreadProxy::SetDeferMainFrameUpdate(bool defer_main_frame_update) { DCHECK(task_runner_provider_->IsMainThread()); // Deferring commits only makes sense if there's a scheduler. if (!scheduler_on_impl_thread_) return; - if (defer_commits_ == defer_commits) + if (defer_main_frame_update_ == defer_main_frame_update) return; - if (defer_commits) - TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this); + if (defer_main_frame_update) + TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferMainFrameUpdate", + this); else - TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this); + TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferMainFrameUpdate", + this); - defer_commits_ = defer_commits; - scheduler_on_impl_thread_->SetDeferCommits(defer_commits); + defer_main_frame_update_ = defer_main_frame_update; + scheduler_on_impl_thread_->SetDeferMainFrameUpdate(defer_main_frame_update); } bool SingleThreadProxy::CommitRequested() const { @@ -346,6 +350,7 @@ void SingleThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() { single_thread_client_->RequestScheduleComposite(); if (scheduler_on_impl_thread_) scheduler_on_impl_thread_->SetNeedsOneBeginImplFrame(); + needs_impl_frame_ = true; } void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() { @@ -358,6 +363,7 @@ void SingleThreadProxy::SetNeedsCommitOnImplThread() { single_thread_client_->RequestScheduleComposite(); if (scheduler_on_impl_thread_) scheduler_on_impl_thread_->SetNeedsBeginMainFrame(); + commit_requested_ = true; } void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) { @@ -528,6 +534,7 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time, DCHECK(inside_impl_frame_); #endif animate_requested_ = false; + needs_impl_frame_ = false; // Prevent new commits from being requested inside DoBeginMainFrame. // Note: We do not want to prevent SetNeedsAnimate from requesting // a commit here. @@ -660,6 +667,14 @@ void SingleThreadProxy::SetRenderFrameObserver( host_impl_->SetRenderFrameObserver(std::move(observer)); } +void SingleThreadProxy::UpdateBrowserControlsState( + BrowserControlsState constraints, + BrowserControlsState current, + bool animate) { + host_impl_->browser_controls_manager()->UpdateBrowserControlsState( + constraints, current, animate); +} + bool SingleThreadProxy::WillBeginImplFrame(const viz::BeginFrameArgs& args) { DebugScopedSetImplThread impl(task_runner_provider_); #if DCHECK_IS_ON() @@ -685,12 +700,18 @@ void SingleThreadProxy::ScheduledActionSendBeginMainFrame( << "BeginMainFrame should only be sent inside a BeginImplFrame"; #endif + host_impl_->WillSendBeginMainFrame(); task_runner_provider_->MainThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&SingleThreadProxy::BeginMainFrame, weak_factory_.GetWeakPtr(), begin_frame_args)); host_impl_->DidSendBeginMainFrame(); } +void SingleThreadProxy::FrameIntervalUpdated(base::TimeDelta interval) { + DebugScopedSetMainThread main(task_runner_provider_); + single_thread_client_->FrameIntervalUpdated(interval); +} + void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() { layer_tree_host_->BeginMainFrameNotExpectedSoon(); } @@ -713,9 +734,10 @@ void SingleThreadProxy::BeginMainFrame( } commit_requested_ = false; + needs_impl_frame_ = false; animate_requested_ = false; - if (defer_commits_) { + if (defer_main_frame_update_) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", TRACE_EVENT_SCOPE_THREAD); BeginMainFrameAbortedOnImplThread( @@ -742,7 +764,7 @@ void SingleThreadProxy::BeginMainFrame( // At this point the main frame may have deferred commits to avoid committing // right now. - if (defer_commits_ || begin_frame_args.animate_only) { + if (defer_main_frame_update_ || begin_frame_args.animate_only) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame", TRACE_EVENT_SCOPE_THREAD); BeginMainFrameAbortedOnImplThread( @@ -775,7 +797,8 @@ void SingleThreadProxy::DoBeginMainFrame( layer_tree_host_->WillBeginMainFrame(); layer_tree_host_->BeginMainFrame(begin_frame_args); layer_tree_host_->AnimateLayers(begin_frame_args.frame_time); - layer_tree_host_->RequestMainFrameUpdate(); + layer_tree_host_->RequestMainFrameUpdate( + false /* record_main_frame_metrics */); } void SingleThreadProxy::DoPainting() { @@ -877,6 +900,10 @@ void SingleThreadProxy::DidNotProduceFrame(const viz::BeginFrameAck& ack) { host_impl_->DidNotProduceFrame(ack); } +void SingleThreadProxy::WillNotReceiveBeginFrame() { + host_impl_->DidNotNeedBeginFrame(); +} + void SingleThreadProxy::DidReceiveCompositorFrameAck() { layer_tree_host_->DidReceiveCompositorFrameAck(); } diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h index 0ff0f79de6e..ca922056575 100644 --- a/chromium/cc/trees/single_thread_proxy.h +++ b/chromium/cc/trees/single_thread_proxy.h @@ -51,7 +51,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void SetNextCommitWaitsForActivation() override; bool RequestedAnimatePending() override; void NotifyInputThrottledUntilCommit() override {} - void SetDeferCommits(bool defer_commits) override; + void SetDeferMainFrameUpdate(bool defer_main_frame_update) override; bool CommitRequested() const override; void Start() override; void Stop() override; @@ -67,16 +67,15 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) override; - // Blink layout tests might call into this even though an unthreaded CC - // doesn't have BrowserControls itself. void UpdateBrowserControlsState(BrowserControlsState constraints, BrowserControlsState current, - bool animate) override {} + bool animate) override; // SchedulerClient implementation bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override; void DidFinishImplFrame() override; void DidNotProduceFrame(const viz::BeginFrameAck& ack) override; + void WillNotReceiveBeginFrame() override; void ScheduledActionSendBeginMainFrame( const viz::BeginFrameArgs& args) override; DrawResult ScheduledActionDrawIfPossible() override; @@ -90,6 +89,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void SendBeginMainFrameNotExpectedSoon() override; void ScheduledActionBeginMainFrameNotExpectedUntil( base::TimeTicks time) override; + void FrameIntervalUpdated(base::TimeDelta interval) override; size_t CompositedAnimationsCount() const override; size_t MainThreadAnimationsCount() const override; bool CurrentFrameHadRAF() const override; @@ -174,10 +174,11 @@ class CC_EXPORT SingleThreadProxy : public Proxy, bool inside_impl_frame_; #endif bool inside_draw_; - bool defer_commits_; + bool defer_main_frame_update_; bool animate_requested_; bool commit_requested_; bool inside_synchronous_composite_; + bool needs_impl_frame_; // True if a request to the LayerTreeHostClient to create an output surface // is still outstanding. diff --git a/chromium/cc/trees/transform_node.cc b/chromium/cc/trees/transform_node.cc index c43fd23fbe1..9964f16880b 100644 --- a/chromium/cc/trees/transform_node.cc +++ b/chromium/cc/trees/transform_node.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/trace_event/trace_event_argument.h" +#include "cc/trees/transform_node.h" +#include "base/trace_event/traced_value.h" #include "cc/base/math_util.h" #include "cc/layers/layer.h" #include "cc/trees/property_tree.h" -#include "cc/trees/transform_node.h" #include "ui/gfx/geometry/point3_f.h" namespace cc { diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h index 931867550f8..c8f8ebf8505 100644 --- a/chromium/cc/trees/transform_node.h +++ b/chromium/cc/trees/transform_node.h @@ -6,6 +6,7 @@ #define CC_TREES_TRANSFORM_NODE_H_ #include "cc/cc_export.h" +#include "cc/trees/element_id.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/transform.h" diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc index c4b44c933c8..c31289f46cf 100644 --- a/chromium/cc/trees/tree_synchronizer.cc +++ b/chromium/cc/trees/tree_synchronizer.cc @@ -87,6 +87,25 @@ void PushLayerList(OwnedLayerImplMap* old_layers, } template <typename LayerTreeType> +void PushElementsInPropertyTreesTo(LayerTreeType* host, + LayerTreeImpl* tree_impl) { + for (auto id_iter = tree_impl->elements_in_property_trees().begin(); + id_iter != tree_impl->elements_in_property_trees().end();) { + const auto& id = *(id_iter++); + if (!host->elements_in_property_trees().count(id)) + tree_impl->RemoveFromElementLayerList(id); + } + + for (const auto& id : host->elements_in_property_trees()) { + if (!tree_impl->IsElementInLayerList(id)) { + // TODO(flackr): We should expose adding element ids without a + // layer pointer. + tree_impl->AddToElementLayerList(id, nullptr); + } + } +} + +template <typename LayerTreeType> void SynchronizeTreesInternal(LayerTreeType* source_tree, LayerTreeImpl* tree_impl, PropertyTrees* property_trees) { @@ -154,6 +173,8 @@ void TreeSynchronizer::PushLayerProperties(LayerTreeImpl* pending_tree, PushLayerPropertiesInternal(layers.begin(), layers.end(), active_tree); PushLayerPropertiesInternal(picture_layers.begin(), picture_layers.end(), active_tree); + if (pending_tree->settings().use_layer_lists) + PushElementsInPropertyTreesTo(pending_tree, active_tree); pending_tree->ClearLayersThatShouldPushProperties(); } @@ -163,6 +184,10 @@ void TreeSynchronizer::PushLayerProperties(LayerTreeHost* host_tree, TRACE_EVENT1("cc", "TreeSynchronizer::PushLayerPropertiesTo.Main", "layer_count", layers.size()); PushLayerPropertiesInternal(layers.begin(), layers.end(), impl_tree); + // When using layer lists, we may not have layers for all property tree + // node ids and need to synchronize the registered id list. + if (host_tree->IsUsingLayerLists()) + PushElementsInPropertyTreesTo(host_tree, impl_tree); host_tree->ClearLayersThatShouldPushProperties(); } diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc index c49b0f0fb1c..547dccae6ef 100644 --- a/chromium/cc/trees/tree_synchronizer_unittest.cc +++ b/chromium/cc/trees/tree_synchronizer_unittest.cc @@ -131,13 +131,44 @@ void ExpectTreesAreIdentical(Layer* root_layer, } class TreeSynchronizerTest : public testing::Test { + public: + void ResetLayerTreeHost(const LayerTreeSettings& settings) { + host_ = FakeLayerTreeHost::Create(&client_, &task_graph_runner_, + animation_host_.get(), settings); + host_->host_impl()->CreatePendingTree(); + } + + scoped_refptr<Layer> SetupScrollLayer() { + FakeLayerTreeHostImpl* host_impl = host_->host_impl(); + + scoped_refptr<Layer> layer_tree_root = Layer::Create(); + scoped_refptr<Layer> scroll_layer = Layer::Create(); + + ElementId scroll_element_id = ElementId(5); + scroll_layer->SetElementId(scroll_element_id); + + layer_tree_root->AddChild(scroll_layer); + + scroll_layer->SetScrollable(gfx::Size(1, 1)); + scroll_layer->SetBounds(gfx::Size(10, 10)); + + host_->SetRootLayer(layer_tree_root); + host_->BuildPropertyTreesForTesting(); + host_->CommitAndCreatePendingTree(); + host_impl->ActivateSyncTree(); + + ExpectTreesAreIdentical(layer_tree_root.get(), + host_impl->active_tree()->root_layer_for_testing(), + host_impl->active_tree()); + + return scroll_layer; + } + protected: TreeSynchronizerTest() - : animation_host_(AnimationHost::CreateForTesting(ThreadInstance::MAIN)), - host_(FakeLayerTreeHost::Create(&client_, - &task_graph_runner_, - animation_host_.get())) { - host_->host_impl()->CreatePendingTree(); + : animation_host_(AnimationHost::CreateForTesting(ThreadInstance::MAIN)) { + LayerTreeSettings settings; + ResetLayerTreeHost(settings); } FakeLayerTreeHostClient client_; @@ -658,7 +689,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) { // Pull ScrollOffset delta for main thread, and change offset on main thread std::unique_ptr<ScrollAndScaleSet> scroll_info(new ScrollAndScaleSet()); - scroll_tree.CollectScrollDeltas(scroll_info.get(), ElementId()); + scroll_tree.CollectScrollDeltas(scroll_info.get(), ElementId(), + settings.commit_fractional_scroll_deltas); host_->proxy()->SetNeedsCommit(); host_->ApplyScrollAndScale(scroll_info.get()); EXPECT_EQ(gfx::ScrollOffset(20, 30), scroll_layer->CurrentScrollOffset()); @@ -741,5 +773,53 @@ TEST_F(TreeSynchronizerTest, RefreshPropertyTreesCachedData) { transform_layer->transform_tree_index(), host_impl->active_tree())); } +TEST_F(TreeSynchronizerTest, RoundedScrollDeltasOnCommit) { + LayerTreeSettings settings; + settings.commit_fractional_scroll_deltas = false; + ResetLayerTreeHost(settings); + + host_->InitializeSingleThreaded(&single_thread_client_, + base::ThreadTaskRunnerHandle::Get()); + + scoped_refptr<Layer> scroll_layer = SetupScrollLayer(); + + // Scroll the layer by a fractional amount. + FakeLayerTreeHostImpl* host_impl = host_->host_impl(); + LayerImpl* scroll_layer_impl = + host_impl->active_tree()->LayerById(scroll_layer->id()); + scroll_layer_impl->ScrollBy(gfx::Vector2dF(0, 1.75f)); + + // When we collect the scroll deltas, we should have truncated the fractional + // part because the commit_fractional_scroll_deltas setting is enabled. + std::unique_ptr<ScrollAndScaleSet> scroll_info = + host_impl->ProcessScrollDeltas(); + ASSERT_EQ(1u, scroll_info->scrolls.size()); + EXPECT_EQ(2.f, scroll_info->scrolls[0].scroll_delta.y()); +} + +TEST_F(TreeSynchronizerTest, PreserveFractionalScrollDeltasOnCommit) { + LayerTreeSettings settings; + settings.commit_fractional_scroll_deltas = true; + ResetLayerTreeHost(settings); + + host_->InitializeSingleThreaded(&single_thread_client_, + base::ThreadTaskRunnerHandle::Get()); + + scoped_refptr<Layer> scroll_layer = SetupScrollLayer(); + + // Scroll the layer by a fractional amount. + FakeLayerTreeHostImpl* host_impl = host_->host_impl(); + LayerImpl* scroll_layer_impl = + host_impl->active_tree()->LayerById(scroll_layer->id()); + scroll_layer_impl->ScrollBy(gfx::Vector2dF(0, 1.75f)); + + // When we collect the scroll deltas, we should keep the fractional part + // because the commit_fractional_scroll_deltas setting is disabled. + std::unique_ptr<ScrollAndScaleSet> scroll_info = + host_impl->ProcessScrollDeltas(); + ASSERT_EQ(1u, scroll_info->scrolls.size()); + EXPECT_EQ(1.75f, scroll_info->scrolls[0].scroll_delta.y()); +} + } // namespace } // namespace cc |