-
Notifications
You must be signed in to change notification settings - Fork 28.8k
[cupertino] improve cupertino picker performance by using at most one opacity layer #124719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[cupertino] improve cupertino picker performance by using at most one opacity layer #124719
Conversation
Letting this bake to see if any existing tests fail 😄 |
Previously with a cupertino picker containing ~N items, we would end up with N opacity layers. Now we only have 1 for all offcenter widgets and potentially 2 more for partially offcenter items - max of 3. |
Actually we can go further and combine all partially opaque shapes together, this gives us a single opacity layer regardless of the number of items in the picker. |
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
I've looked through the goldens and in general they look OK to me. The change in color is easily explained by different behavior for clipping then opacity versus opacity then clipping. The only concern would be the scale of g3 impact. |
RenderBox? childToPaint = firstChild; | ||
while (childToPaint != null) { | ||
final ListWheelParentData childParentData = childToPaint.parentData! as ListWheelParentData; | ||
_paintTransformedChild(childToPaint, context, offset, childParentData.offset, center: false); | ||
childToPaint = childAfter(childToPaint); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we can refactor this into a method (with center
as a configurable argument) and call that here, above, and below to de-dup this a little and show that it is essentially doing the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// | ||
// If [center] is true, only children that overlap with the center section | ||
// will be painted. If [center] is false, only children that do not overlap | ||
// will be painted. Opacity is only applied to the partially overlapping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment about Opacity here actually true? My understanding was that opacity is fully controlled from outside this method now? I.e. it is up to the caller to apply opacity where necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
@@ -828,22 +828,51 @@ class RenderListWheelViewport | |||
|
|||
/// Paints all children visible in the current viewport. | |||
void _paintVisibleChildren(PaintingContext context, Offset offset) { | |||
if (overAndUnderCenterOpacity >= 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we also go down this code path if useMagnifier is false? Seems like in that case the other code path would paint some children twice since _paintTransformedChild ignores the value of center in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see line 907
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the magnifier cannot be disabled if there is opacity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that enforced anywhere in the API that useMagnifier
must be true if overAndUnderCenterOpacity
is less than 1? Or is it if there is opacity the value of useMagnifier
is just (silently) ignored?
This is confusing, but I guess not a problem of this PR...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the value of use magnifier is just ignored
@@ -876,7 +905,7 @@ class RenderListWheelViewport | |||
|
|||
final bool shouldApplyOffCenterDim = overAndUnderCenterOpacity < 1; | |||
if (useMagnifier || shouldApplyOffCenterDim) { | |||
_paintChildWithMagnifier(context, offset, child, transform, offsetToCenter, untransformedPaintingCoordinates); | |||
_paintChildWithMagnifier(context, offset, child, transform, offsetToCenter, untransformedPaintingCoordinates, center: center); | |||
} else { | |||
_paintChildCylindrically(context, offset, child, transform, offsetToCenter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we assert that center is null if we go down the else branch?
Actually, the fact that this branch ignores center silently makes the code kinda hard to follow (and I think it is also the source of a bug in the current implementation, see my comment about useMagnifier above). Maybe we need to refactor this somehow to make it easier to follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we assert that center is null if we go down the else branch?
What about this one? Since this is already pretty confusing it may be worthwhile to put a guardrail in place for when this gets refactored to make the caller instantly aware of the fact that their specification of center is not doing what they may think it is doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the assert. I'm not in love with this code but I don't see a nice way to re-arrange it all...
// will be painted. If [center] is false, only children that do not overlap | ||
// will be painted. Opacity is only applied to the partially overlapping | ||
// children painted when [center] is true. | ||
// If center is `null` this logic is ignored entirely. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe clearer: if center is null all children will be painted?
From some investigation on my part, its not currently possible to disable the magnifier if there is any opacity. This change keeps that behavior, though it is a bit confusing. I've tried to clarify the comments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -828,22 +828,51 @@ class RenderListWheelViewport | |||
|
|||
/// Paints all children visible in the current viewport. | |||
void _paintVisibleChildren(PaintingContext context, Offset offset) { | |||
if (overAndUnderCenterOpacity >= 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that enforced anywhere in the API that useMagnifier
must be true if overAndUnderCenterOpacity
is less than 1? Or is it if there is opacity the value of useMagnifier
is just (silently) ignored?
This is confusing, but I guess not a problem of this PR...
@@ -828,22 +828,42 @@ class RenderListWheelViewport | |||
|
|||
/// Paints all children visible in the current viewport. | |||
void _paintVisibleChildren(PaintingContext context, Offset offset) { | |||
// Note that the magnifier cannot be turned off if the opacity is less than |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: per style guide just remove the "note that" at the beginning here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -876,7 +905,7 @@ class RenderListWheelViewport | |||
|
|||
final bool shouldApplyOffCenterDim = overAndUnderCenterOpacity < 1; | |||
if (useMagnifier || shouldApplyOffCenterDim) { | |||
_paintChildWithMagnifier(context, offset, child, transform, offsetToCenter, untransformedPaintingCoordinates); | |||
_paintChildWithMagnifier(context, offset, child, transform, offsetToCenter, untransformedPaintingCoordinates, center: center); | |||
} else { | |||
_paintChildCylindrically(context, offset, child, transform, offsetToCenter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we assert that center is null if we go down the else branch?
What about this one? Since this is already pretty confusing it may be worthwhile to put a guardrail in place for when this gets refactored to make the caller instantly aware of the fact that their specification of center is not doing what they may think it is doing?
…most one opacity layer (flutter/flutter#124719)
…most one opacity layer (flutter/flutter#124719)
flutter/flutter@00171b0...50171bb 2023-04-16 engine-flutter-autoroll@skia.org Roll Flutter Engine from da0805a9cf03 to 4a998b73a2df (5 revisions) (flutter/flutter#124944) 2023-04-16 engine-flutter-autoroll@skia.org Roll Flutter Engine from feb476b7b991 to da0805a9cf03 (4 revisions) (flutter/flutter#124933) 2023-04-15 engine-flutter-autoroll@skia.org Roll Flutter Engine from ee66f0d6f2c9 to feb476b7b991 (2 revisions) (flutter/flutter#124929) 2023-04-15 jonahwilliams@google.com Revert "[framework] use shader tiling instead of repeated calls to drawImage" (flutter/flutter#124640) 2023-04-15 jonahwilliams@google.com [cupertino] improve cupertino picker performance by using at most one opacity layer (flutter/flutter#124719) 2023-04-15 andrewrkolos@gmail.com [flutter_tools] Remove `Version.unknown` (flutter/flutter#124771) 2023-04-15 engine-flutter-autoroll@skia.org Roll Flutter Engine from 41c1ea9a8283 to ee66f0d6f2c9 (2 revisions) (flutter/flutter#124923) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC bmparr@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
… opacity layer (flutter#124719) Fixes flutter#124703 Rather than applying an opacity layer per picker item, apply them to all partially opaque picker items at once. This dramatically improves performance for impeller, by reducing the number of required subpasses and texture allocations signficantly. Before: Doesn't finish, 100s of passes After:   See also: flutter#124658
flutter/flutter@00171b0...50171bb 2023-04-16 engine-flutter-autoroll@skia.org Roll Flutter Engine from da0805a9cf03 to 4a998b73a2df (5 revisions) (flutter/flutter#124944) 2023-04-16 engine-flutter-autoroll@skia.org Roll Flutter Engine from feb476b7b991 to da0805a9cf03 (4 revisions) (flutter/flutter#124933) 2023-04-15 engine-flutter-autoroll@skia.org Roll Flutter Engine from ee66f0d6f2c9 to feb476b7b991 (2 revisions) (flutter/flutter#124929) 2023-04-15 jonahwilliams@google.com Revert "[framework] use shader tiling instead of repeated calls to drawImage" (flutter/flutter#124640) 2023-04-15 jonahwilliams@google.com [cupertino] improve cupertino picker performance by using at most one opacity layer (flutter/flutter#124719) 2023-04-15 andrewrkolos@gmail.com [flutter_tools] Remove `Version.unknown` (flutter/flutter#124771) 2023-04-15 engine-flutter-autoroll@skia.org Roll Flutter Engine from 41c1ea9a8283 to ee66f0d6f2c9 (2 revisions) (flutter/flutter#124923) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC bmparr@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Fixes #124703
Rather than applying an opacity layer per picker item, apply them to all partially opaque picker items at once. This dramatically improves performance for impeller, by reducing the number of required subpasses and texture allocations signficantly.
Before:
Doesn't finish, 100s of passes
After:
See also:
#124658