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] partial repaint for Impeller/iOS. #40959

Merged
merged 29 commits into from
Apr 26, 2023

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Apr 6, 2023

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.

if (!source_region.has_value()) {
return true; // Nothing to blit.
}
// // Clip the destination image.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing code here is wrong. Need to figure out why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This didn't work as expected if the source region isn't the entire size of the source texture. Since I changed the impeller impl to use a translate instead of just a clip we don't hit this case anymore.

@jonahwilliams jonahwilliams marked this pull request as ready for review April 18, 2023 22:28
return current_drawable;
}

std::unique_ptr<SurfaceMTL> SurfaceMTL::WrapCurrentMetalLayerDrawable(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split this and the above into two functions, so that we can ge the clip rect for DRM before we construct the render target, which is required for conditionally adjusting the strategy.

@jonahwilliams
Copy link
Member Author

actually ... 500ns isn't really a long time. We could unconditionally do the blit if it were easier.

@flutter-dashboard
Copy link

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.

Changes reported for pull request #40959 at sha 5081bb7

@jonahwilliams
Copy link
Member Author

image changes seem unrelated from canvaskit changes?

@jonahwilliams jonahwilliams requested review from chinmaygarde, dnfield and bdero and removed request for dnfield April 19, 2023 20:03
flow/compositor_context.cc Outdated Show resolved Hide resolved
Copy link
Member

@knopp knopp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the nit below this looks good to me. Thanks!

}

void Reset() { ignore_damage_ = true; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this could simply be void Reset() { damage_ = std::nullopt; }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly if I do this rendering breaks. I wonder if the logic for computing damage requires all frames to have up to date damage calculations? Or if perhaps the std::nullopt signal is incorrect for frame damage and it should instead be treated as if the entire screen were dirty?

Copy link
Member

@knopp knopp Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It breaks because in that case frame_damage is not properly reported in submit info which breaks tracking of accumulated damage in other two buffers. So the area subsequently repainted in back buffers is smaller than it should be, causing glitches. This is visible in the material progress indicator example when sliding in/out the menu:

glitch.mov

Possible solution might be something like knopp@30c3d61 . Except this doesn't work because it causes ShouldPerformPartialRepaint always return false in subsequent repaints effectively disabling partial repaint completely.

So I'd keep it as it is, maybe add a comment that we need to preserve frame_damage to correctly track accumulated damage for other buffers while at same time reset buffer_damage to disable partial repaint for current buffer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks for the investigation here. I added a comment, but I think it makes sense to keep frame damage because the damage info is still correct a subsequent frame could use this and decide to do a partial repaint.

return true;
}

auto blit_command_buffer = context->CreateCommandBuffer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bdero , if we are doing a final blit for partial repaint, I think I could just hop on the command buffer above and use that? I don't think it actually needs to be empty right, its just a way to ensure that everything else has been scheduled

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this out a bit but ran into some memory corruption issues. not investigating, just moved the blit before the final command buffer creation for now.

layer_tree.Paint(*this, ignore_raster_cache);
}

constexpr float kImpellerRepaintRatio = 0.7f;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a comment about why this number and how to figure out if changing it is helping or hurting things.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const std::shared_ptr<Context>& context,
CAMetalLayer* layer) {
TRACE_EVENT0("impeller", "SurfaceMTL::WrapCurrentMetalLayerDrawable");
TRACE_EVENT0("impeller", "SurfaceMTL::GetMetalDrawableAndValidate");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are both of these events (this and the one int he new method) helpful?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not!, I removed one

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 26, 2023
@auto-submit
Copy link
Contributor

auto-submit bot commented Apr 26, 2023

auto label is removed for flutter/engine, pr: 40959, due to - The status or check suite Mac Host Engine has failed. Please fix the issues identified (or deflake) before re-applying this label.

@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Apr 26, 2023
@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 26, 2023
@auto-submit auto-submit bot merged commit 20be523 into flutter:main Apr 26, 2023
32 checks passed
@jonahwilliams jonahwilliams deleted the partial_repaint_impeller_2 branch April 26, 2023 21:13
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 26, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 27, 2023
jonahwilliams pushed a commit to flutter/flutter that referenced this pull request Apr 27, 2023
…125593)

flutter/engine@cf97541...d4ca524

2023-04-27 skia-flutter-autoroll@skia.org Roll Skia from 20a1c61c5597 to
d315ab065af3 (5 revisions) (flutter/engine#41535)
2023-04-26 jonahwilliams@google.com Revert "[Impeller] Use a device
buffer for SkBitmap allocation, use Linear texture on Metal backend."
(flutter/engine#41533)
2023-04-26 xilaizhang@google.com [codesign] Add pinned xcode version as
property to mac android aot engine (flutter/engine#41518)
2023-04-26 bdero@google.com [Impeller] Coerce opaque ColorSourceContents
to Source (flutter/engine#41525)
2023-04-26 skia-flutter-autoroll@skia.org Roll Skia from 3fea88565a83 to
20a1c61c5597 (3 revisions) (flutter/engine#41530)
2023-04-26 jonahwilliams@google.com [Impeller] partial repaint for
Impeller/iOS. (flutter/engine#40959)
2023-04-26 30870216+gaaclarke@users.noreply.github.com Updated todo with
github issue link (flutter/engine#41517)
2023-04-26 skia-flutter-autoroll@skia.org Roll Clang from 20d06c833d83
to 5344d8e10bb7 (flutter/engine#41524)
2023-04-26 jonahwilliams@google.com [Impeller] Use a device buffer for
SkBitmap allocation, use Linear texture on Metal backend.
(flutter/engine#41374)
2023-04-26 zanderso@users.noreply.github.com Manual clang roll to
5344d8e10bb7d8672d4bfae8adb010465470d51b (flutter/engine#41520)
2023-04-26 zanderso@users.noreply.github.com Download and use the goma
client from cipd (flutter/engine#41488)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the
revert to ensure that a human
is aware of the problem.

To file a bug in Flutter:
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App e: impeller
Projects
No open projects
Archived in project
4 participants