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] DRM/ Partial Repaint for Impeller #124526

Closed
jonahwilliams opened this issue Apr 10, 2023 · 4 comments · Fixed by flutter/engine#40959
Closed

[Impeller] DRM/ Partial Repaint for Impeller #124526

jonahwilliams opened this issue Apr 10, 2023 · 4 comments · Fixed by flutter/engine#40959
Labels
e: impeller Impeller rendering backend issues and features requests engine flutter/engine repository. See also e: labels. P3 Issues that are less important to the Flutter project

Comments

@jonahwilliams
Copy link
Member

On the Metal and Vulkan backends of Impeller, the process for enabling DRM is fairly straightforward, though there are a few Impeller specific implementation changes and some required benchmarking.

To start with, the damage rect will be fully computed before Impeller has started the frame workload. Flow will inform Impeller of this damage rect indirectly by first applying a clip to the canvas: https://github.com/flutter/engine/blob/main/flow/compositor_context.cc#L153-L169

For Impeller, we should device a better technique of sending the clip rect that lets us actually reduce surface sizes. Additionally, sending the ClipRect and then clearing will force more work from impeller than vice versa.

Now, the expectation is that the texture we acquire from the metal layer will be rendered into with a load instead of a clear so that the older content persists. However, in Impeller we use this texture as the resolve texture for the root multisample render pass. It does not seem like we can use a resolve texture without implicitly clearing it. See WrapCurrentMetalLayerDrawable in surface_mtl.mm.

If so, we may need to use a different texture for the resolve texture and the blit that texture (according to the damage) rect into the actual metal layer's texture. This would be marginally more expensive, so we'd need to benchmark. We could perform this operation conditionally based on whether or not the damage rect was sufficiently large.

FYI @knopp

@jonahwilliams jonahwilliams added engine flutter/engine repository. See also e: labels. P3 Issues that are less important to the Flutter project e: impeller Impeller rendering backend issues and features requests labels Apr 10, 2023
@knopp
Copy link
Member

knopp commented Apr 11, 2023

IIRC before partial repaint (and impeller) the actual metal surface was only requested in submit callback. In submit callback you should be able to access SubmitInfo, which contains both frame_damage (part of front buffer that needs to be recomposed) as well as buffer_damage, which is part of the frame that will be written to.

The reason why for partial repaint the metal surface is requested in AcquireFrame is that we need to know, which of the three different drawables used by CAMetalLayer we're gonna get. This affects existing_damage which must be taken into account when computing dirty region. The existing_damage basically means the area where the current drawable lags behind the front buffer.

We need to track this per drawable. Metal does this weird thing that it sometimes keeps flipping between only two of the drawables for dozens of frames meaning that third drawable gets quite out of sync.

So at very least for the non-impeller path, while the metal drawable gets requested in acquire frame, it is not actually used until submit (at which point we know the buffer_damage).

@jonahwilliams
Copy link
Member Author

Making good progress here: flutter/engine#40959, though clip rect seems to be slightly off. I think I'm probably make a small mistake somewhere. Don't know why the frame count claims to be lower, but I added some additional short circuiting that might be tickling that a bit.

Testing on the blinking cursor in flutter gallery

Without Patch (Impeller)

image

With Patch (Impeller)

image

Skia

image

@jonahwilliams
Copy link
Member Author

ahh, the issue is a bug in our blit pass...that can be fixed

auto-submit bot pushed a commit to flutter/engine that referenced this issue Apr 26, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Implements partial repaint for Impeller.

Fixes flutter/flutter#124526

The new code that manages the damage regions is more or less a copy paste from the existing Skia implementation. Compared to Skia, there are a few differences:

Normally Impeller wants to use the drawable as the resolve texture for the root MSAA pass. Unfortunately this will unconditonally clear that texture. Thus to do a partial repaint, we have to allocate a separate texture to resolve to and then blit into the drawable.

The blit seems to take about 500ns for a full screen on an iPhone 13. That implies that partial repaint is likely not worth doing if the screen is significantly changed. Thus I've added code in compositor_context.cc that computes the percentage of width or height that is part of the dirty rect. Above a threshold of (abitrarily chosen) 70%, we just render as normal. This should mean there is only a very minor hit from performing the diff on screens that are highly changed.

The other special case, is that sometimes we get damage rects that are empty - that is the drawable is already completely up to date with what we want to render. IN that case I shortcircuit all of the impeller code and just present immediately. I previously tried returning without a present but this resulted in Xcode reporting dropped frames. One caveat here is that if you use the XCode frame debugger and attempt to capture a frame where we early present, then it will claim it couldn't capture any command buffers (because we didn't create any).

To facilitate all of this, I added some additonal plumbing so that the impeller surface can get the clip rect from the submit info. Additionally, rather than using a clip rect impeller will translate and then shrink the root surface texture. This reduces memory usage compared to just clippling.
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
e: impeller Impeller rendering backend issues and features requests engine flutter/engine repository. See also e: labels. P3 Issues that are less important to the Flutter project
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants