Skip to content
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

[Impeller] better handle allocation herustics of Android slide in page transition. #56762

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Nov 22, 2024

For flutter/flutter#158881

The new Android m3 page transition animates a saveLayer w/ opacity + slide in animation. See example video from linked PR:

387832059-a806f25d-8564-4cad-8dfc-eb4585294181.mov

On each frame, we intersect the coverage rect of this saveLayer contents with the screen rect, and shrink it to a partial rectangle. But this changes each frame, which forces us to re-allocate a large texture each frame, causing performance issues.

Why not ignore the cull rect entirely? We sometimes ignore the cull rect for the image filter layer for similar reasons, but from observation, the sizes of these saveLayer can be slightly larger than the screen for flutter gallery. Instead, I attempted to use the cull rect size to shrink the saveLayer by shifting the origin before intersecting.

I think this should be safe to do, as I believe it could only leave the coverage as larger than it would have been and not smaller.

@jonahwilliams
Copy link
Member Author

@flar / @gaaclarke does this make sense to you?

@jonahwilliams jonahwilliams marked this pull request as ready for review November 22, 2024 21:58
@flar
Copy link
Contributor

flar commented Nov 22, 2024

The algorithm feels highly speculative and very specific to the sliding transition. The two coverages could differ by a large shift and we'd allocate a coverage that was very greatly larger than we need, wasting rendering time.

I like the fact that it first checks if there is any intersection at all - that at least prevents this over-estimated coverage when the source isn't even visible. But, what if the transformed intersection is 5x5 but the shifted intersection is 500x700? We'd allocate 14k times as many pixels as we need without even batting an eye. And what if that particular case happened to be static so we paid that price on every frame without any indication that it was animating towards a larger intersection?

If this is to prevent thrashing, what if we just increased the granularity of temporary texture allocations to minimize the number without trying to completely eliminate them?

@flar
Copy link
Contributor

flar commented Nov 22, 2024

Overall I'd vote against this particular heuristic without any other limits or predictive evidence guiding its actions, but I am intrigued by the concept of trying to avoid varying allocations during transitions.

@jonahwilliams
Copy link
Member Author

Re: lack of limits, that is a good point. For the slide in, I think the values are only in the 10 to 15% range. So I could limit this by limiting how much I'm willing to slide it over.

The algorithm feels highly speculative and very specific to the sliding transition

It is highly specific to that transition, but that transition will be the default for all android applications soon - so its going to be extremely widespread.

@flar
Copy link
Contributor

flar commented Nov 23, 2024

One thought is that we could advertise transitions to the engine by having something along the lines of ui.Canvas.interpolateTransorm(matrixA, matrixB, t) - that way we see the entire range of transforms we will encounter and the t value specifies the specific transition point currently in effect.

@flar
Copy link
Contributor

flar commented Nov 23, 2024

Re: lack of limits, that is a good point. For the slide in, I think the values are only in the 10 to 15% range. So I could limit this by limiting how much I'm willing to slide it over.

Also, this form of performance improvement is a compromise. It's not "simply" saving us thrashing the cache, it's causing us to render more in lieu of thrashing the cache.

We should only render the true intersection on this frame even if we allocate what we believe will be the entire operation. I don't see that addressed here. Perhaps return a {intersected bounds, potential size} tuple?

@flar
Copy link
Contributor

flar commented Nov 24, 2024

Another idea, the transform interpolation could be an internal thing with TransformLayer if it could understand that it is part of an animation and tell its engine layer "Hey, I'm going from A to B and currently at state t" without having to modify the ui.Canvas API in a confusing way. (iow - It might be an internal call on DlCanvas invoked from the TransformLayer, but not visible on ui.Canvas).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants