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

PlatformViews needs clipRect. #37107

Merged
merged 2 commits into from
Dec 3, 2022
Merged

Conversation

endless7
Copy link
Contributor

@endless7 endless7 commented Oct 28, 2022

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@dnfield
Copy link
Contributor

dnfield commented Oct 28, 2022

Is there a bug for this somewhere? Is there a test case that fails if this code isn't present?

@jmagman
Copy link
Member

jmagman commented Nov 9, 2022

Is there a test case that fails if this code isn't present?

+1 this PR needs tests. See https://github.com/flutter/engine/pull/37434/files#diff-2110fb85ed5e9825880b29cbb4c1007a20592f08be07edb0b87e5138cb0c2dd0R1481 for a similar-ish example of how this could be done.

cc @cyanglaz

@flar
Copy link
Contributor

flar commented Nov 9, 2022

Is there a bug for this somewhere? Is there a test case that fails if this code isn't present?

I also asked for clarification on the issue itself. The issue seems to say "this line of Skia code looks at the clip bounds" at the justification for why this is being done. There is no description for how an application is affected.

@flar
Copy link
Contributor

flar commented Nov 10, 2022

It looks like this is dealing with the case where a partial repaint (computed by DiffContext) is causing only a small region of the display to be updated. The entire overlay is rendered as if it were a full-screen update rather than only clipping to the part that needs to be updated.

I think @cyanglaz should look at this to verify, but it sounds like the clip can help reduce operations. The associated github-issue seems focused on triggering the BBH processing in Skia, but that is a small optimization that only helps with incredibly complex scenes (such as the developer that was drawing hundreds of thousands of drawLine calls that were 99% offscreen). The main gain here for most apps would be not rendering pixels that aren't necessary for the partial-screen update - and a combination of Skia's built-in per-operation clip culling and pre-rendering BBH filtering will reduce that work further as well.

The larger question is why we are rendering into an oversized surface? If that is due to us simply ignoring the partial repaint clip when we allocate the surface on each frame then we can save even more by allocating a surface that is the right size. If this is a case of reusing either a surface from a previous (fully rendered) frame, or reusing a pool of surfaces that may be larger than we need to avoid allocation overhead on every frame - then the clip would be needed to avoid overdraw.

@cyanglaz
Copy link
Contributor

I looked at the original design doc and it doesn't seem to mention why we can't clip the canvas: go/flutter-unobstructed-platform-views

Because the overlay is already clipped by the overlay_view_wrapper from iOS perspective, see: (https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm#L743), the content that outside of the overlay is not going to be displayed with or without the canvas being clipped.

allocating a surface that is the right size

The content that we paint is in the coordinate space of the entire screen, so to make the surface smaller, we will need to update content to paint on a different coordinate, maybe something like:

  std::unique_ptr<SurfaceFrame> frame = layer->surface->AcquireFrame(SkSize::Make(rect.width:(), rect.height());
  SkCanvas* overlay_canvas = frame->SkiaCanvas();
  overlay_canvas->translate(-rect.x(), -rect.y());

@flar
Copy link
Contributor

flar commented Nov 11, 2022

I looked at the original design doc and it doesn't seem to mention why we can't clip the canvas: go/flutter-unobstructed-platform-views

That link doesn't go anywhere. Is it supposed to be a flutter.dev go link?

Because the overlay is already clipped by the overlay_view_wrapper from iOS perspective, see: (https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm#L743), the content that outside of the overlay is not going to be displayed with or without the canvas being clipped.

This isn't a "stuff is showing up that shouldn't be" kind of functionality bug. The output is correct.

This is a "we are rendering stuff that is not going to be shown" type of "wasted effort hurts performance" kind of bug. iOS my be clipping the results, but we are still doing work to create those pixels that we won't need in the end.

@cyanglaz
Copy link
Contributor

The link is fixed and it should work now. It is an internal go link.

This is a "we are rendering stuff that is not going to be shown" type of "wasted effort hurts performance" kind of bug. iOS my be clipping the results, but we are still doing work to create those pixels that we won't need in the end.

Understood, I was just wondering if making the surface smaller and keep the content as is would increase performance, or we would actually need to clip the content to reduce unnecessary rendering. Skia or Impeller should have some optimization if the content is outside of the canvas?

@flar
Copy link
Contributor

flar commented Nov 11, 2022

This is a "we are rendering stuff that is not going to be shown" type of "wasted effort hurts performance" kind of bug. iOS my be clipping the results, but we are still doing work to create those pixels that we won't need in the end.

Understood, I was just wondering if making the surface smaller and keep the content as is would increase performance, or we would actually need to clip the content to reduce unnecessary rendering. Skia or Impeller should have some optimization if the content is outside of the canvas?

By default a Skia canvas will have a clip to the surface it is on, but in this case we are drawing to just a part of that surface, so without the clipRect the only culling that will happen will be to the much larger surface - which is extra work. Normally a scene's bounds is only as big as its content, but some conditions can cause us to draw part of a scene. DiffContext/partial repaints are one case, but there may be others? I didn't get an answer on my question in the github issue as to whether this is triggered by partial repaints or not.

@endless7
Copy link
Contributor Author

endless7 commented Nov 15, 2022

This is a "we are rendering stuff that is not going to be shown" type of "wasted effort hurts performance" kind of bug. iOS my be clipping the results, but we are still doing work to create those pixels that we won't need in the end.

Understood, I was just wondering if making the surface smaller and keep the content as is would increase performance, or we would actually need to clip the content to reduce unnecessary rendering. Skia or Impeller should have some optimization if the content is outside of the canvas?

By default a Skia canvas will have a clip to the surface it is on, but in this case we are drawing to just a part of that surface, so without the clipRect the only culling that will happen will be to the much larger surface - which is extra work. Normally a scene's bounds is only as big as its content, but some conditions can cause us to draw part of a scene. DiffContext/partial repaints are one case, but there may be others? I didn't get an answer on my question in the github issue as to whether this is triggered by partial repaints or not.

Doesn't the partial repaints only happen in comparing two dl? In my understanding repaint and just paint are different cases. I just wonder how the partial repaints works at this case.

@flar
Copy link
Contributor

flar commented Nov 23, 2022

Doesn't the partial repaints only happen in comparing two dl? In my understanding repaint and just paint are different cases. I just wonder how the partial repaints works at this case.

Partial repaint happens when two layer trees are compared during this piece of code:

layer_tree.root_layer()->Diff(&context, prev_root_layer);

That line will run the entire layer tree and compare it to the previous layer tree looking for differences. It accumulates the bounds of the differences and those bounds are handed off to the code that prerolls and paints the layer tree to restrict those operations to the changed region. An individual DisplayListLayer might compare its DL against the one in the previous frame to see if they are the same, but the entire partial repaint process happens across an entire layer tree.

@knopp
Copy link
Member

knopp commented Nov 26, 2022

Partial repaint should be disabled when there are platform views. If it isn't that's a bug. I haven't figured out how partial repaint would interact with multiple surfaces (especially because the z-order can change between frames).

@knopp
Copy link
Member

knopp commented Nov 26, 2022

Also, the number of content needed to be repainted (existing damage) depends on which of two back buffers CALayer gives us. But with platform views there are multiple CALayers (for overlays) - so this may not give correct result.

It seems that right now layer diffing is disabled when thread merging is enabled. Might not be the best way to do this.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

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

LGTM

@flar
Copy link
Contributor

flar commented Dec 1, 2022

It looks like this comes into play in the embedder when we slice up the display lists that live under/over/between the platform views and draw pieces of them with tiny clips. Setting the clip in that case can reduce the pixel count that the GPU has to deal with.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

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

Please add a test as per this comment: #37107 (comment)

@jonahwilliams
Copy link
Member

I investigated this on a slightly simplified example from: flutter/flutter#114712

Without this change average raster is 9.5ms
With this change average raster is 7.5ms

Since this change did not show up in our benchmarks, we should add a case that has some more expensive UI.

@zanderso
Copy link
Member

zanderso commented Dec 2, 2022

Thanks @jonahwilliams! Can this be landed?

@jonahwilliams
Copy link
Member

Lets land the benchmark first, then this one

@jonahwilliams
Copy link
Member

The benchmark change has landed. lets give it some time to build up a few commits and verify it is working correctly. If everything goes according to plan I'll merge this later tonight

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

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

Approved pending Jonah's discretion...

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Dec 3, 2022
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Dec 3, 2022
@auto-submit
Copy link
Contributor

auto-submit bot commented Dec 3, 2022

auto label is removed for flutter/engine, pr: 37107, due to - Please get at least one approved review if you are already a member or two member reviews if you are not a member before re-applying this label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@auto-submit
Copy link
Contributor

auto-submit bot commented Dec 3, 2022

auto label is removed for flutter/engine, pr: 37107, due to Validations Fail.

Copy link
Member

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

LGTM

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Dec 3, 2022
@auto-submit auto-submit bot merged commit f7df812 into flutter:main Dec 3, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Dec 3, 2022
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Dec 3, 2022
…116447)

* bebc12fd0 Roll Skia from 28c1bbab82b8 to 6fdf7181e374 (16 revisions) (flutter/engine#38046)

* 2c1e5efae [Impeller] add --enable-impeller-3d flag to support scene experimentation (flutter/engine#37990)

* 8e11659a8 [canvaskit] Fix Shader program tests (flutter/engine#37644)

* 850c4ad68 [canvaskit] Fix Surface test (flutter/engine#37636)

* f7df812d2 save (flutter/engine#37107)
@flar
Copy link
Contributor

flar commented Dec 4, 2022

Did we file a follow-on Issue to write a test case for this? Or is the benchmark considered the "test case"?

zanderso pushed a commit to zanderso/engine that referenced this pull request Dec 5, 2022
@jonahwilliams
Copy link
Member

For something that is primarily intended to be a performance improvement a benchmark is a sufficient test

itsjustkevin pushed a commit that referenced this pull request Dec 5, 2022
Co-authored-by: JiaJian <33014143+endless7@users.noreply.github.com>
mit-mit pushed a commit to mit-mit/flutter that referenced this pull request Dec 6, 2022
…lutter#116447)

* bebc12fd0 Roll Skia from 28c1bbab82b8 to 6fdf7181e374 (16 revisions) (flutter/engine#38046)

* 2c1e5efae [Impeller] add --enable-impeller-3d flag to support scene experimentation (flutter/engine#37990)

* 8e11659a8 [canvaskit] Fix Shader program tests (flutter/engine#37644)

* 850c4ad68 [canvaskit] Fix Surface test (flutter/engine#37636)

* f7df812d2 save (flutter/engine#37107)
shogohida pushed a commit to shogohida/flutter that referenced this pull request Dec 7, 2022
…lutter#116447)

* bebc12fd0 Roll Skia from 28c1bbab82b8 to 6fdf7181e374 (16 revisions) (flutter/engine#38046)

* 2c1e5efae [Impeller] add --enable-impeller-3d flag to support scene experimentation (flutter/engine#37990)

* 8e11659a8 [canvaskit] Fix Shader program tests (flutter/engine#37644)

* 850c4ad68 [canvaskit] Fix Surface test (flutter/engine#37636)

* f7df812d2 save (flutter/engine#37107)
gspencergoog pushed a commit to gspencergoog/flutter that referenced this pull request Jan 19, 2023
…lutter#116447)

* bebc12fd0 Roll Skia from 28c1bbab82b8 to 6fdf7181e374 (16 revisions) (flutter/engine#38046)

* 2c1e5efae [Impeller] add --enable-impeller-3d flag to support scene experimentation (flutter/engine#37990)

* 8e11659a8 [canvaskit] Fix Shader program tests (flutter/engine#37644)

* 850c4ad68 [canvaskit] Fix Surface test (flutter/engine#37636)

* f7df812d2 save (flutter/engine#37107)
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 needs tests platform-ios
Projects
None yet
8 participants