-
Notifications
You must be signed in to change notification settings - Fork 28.3k
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
Comments
IIRC before partial repaint (and impeller) the actual metal surface was only requested in The reason why for partial repaint the metal surface is requested in 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 |
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) With Patch (Impeller) Skia |
ahh, the issue is a bug in our blit pass...that can be fixed |
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.
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 |
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
The text was updated successfully, but these errors were encountered: