Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Improve ShapeDecoration performance. #108648

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

Merged
merged 10 commits into from
Aug 17, 2022

Conversation

bernaferrari
Copy link
Contributor

@bernaferrari bernaferrari commented Jul 29, 2022

Discussion: #108052

I believe that PR became too big and it is doing too many things at once. This PR is not breaking but might require a g3fix. So I'm splitting it. Easier to fix and easier to track the performance gains.

cc @Hixie. Same code you already reviewed (with an additional comment in box_border.dart).

Edit: I could make this change (really small optimization, only render border if width != 0) yet the code looks horrible. So I'm not making it, yet.
image

@flutter-dashboard flutter-dashboard bot added f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. c: contributor-productivity Team-specific productivity, code health, technical debt. labels Jul 29, 2022
@bernaferrari bernaferrari force-pushed the Faster-ShapeDecoration branch 3 times, most recently from 8142b79 to 4edb88f Compare July 29, 2022 22:35
@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.

For more guidance, visit Writing a golden file test for package:flutter.

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

Changes reported for pull request #108648 at sha 4edb88ff4f45d7e38b5128f3f928c39cdec64f8e

@flutter-dashboard flutter-dashboard bot added the will affect goldens Changes to golden files label Jul 29, 2022
@bernaferrari
Copy link
Contributor Author

bernaferrari commented Jul 29, 2022

I think we should ignore that. It is probably a path vs circle rounding error thing.

@bernaferrari bernaferrari force-pushed the Faster-ShapeDecoration branch from b228ee4 to 4edb88f Compare July 31, 2022 18:59
@Hixie
Copy link
Contributor

Hixie commented Aug 1, 2022

Yeah it is indeed a change in antialiasing. Maybe drawCircle and drawPath differ slightly?

I've marked it as OK.

@Hixie
Copy link
Contributor

Hixie commented Aug 1, 2022

Edit: I could make this change (really small optimization, only render border if width != 0) yet the code looks horrible. So I'm not making it, yet.

Yeah I would not make that change either.

@@ -180,6 +180,17 @@ abstract class BoxBorder extends ShapeBorder {
..addRect(rect);
}

@override
void paintInterior(Canvas canvas, Rect rect, Paint paint, { TextDirection? textDirection }) {
// If `ShapeDecoration(shape: Border.all())`, ShapeDecoration doesn't
Copy link
Contributor

Choose a reason for hiding this comment

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

If -> For?

Maybe clarify this further, explaining that this class only ever paints a rounded border if paint is given one and that this is an extension to the superclass' API.

Copy link
Contributor Author

@bernaferrari bernaferrari Aug 17, 2022

Choose a reason for hiding this comment

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

Thanks! I re-wrote it:

    // For `ShapeDecoration(shape: Border.all())`, a rectangle with sharp edges
    // is always painted. There is no BorderRadius parameter for
    // ShapeDecoration or Border, only for BoxDecoration, which doesn't call
    // this method.

_decoration.shape.getOuterPath(rect.shift(shadow.offset).inflate(shadow.spreadRadius), textDirection: textDirection),
shadow.toPaint(),
);
}),
Copy link
Contributor

Choose a reason for hiding this comment

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

i guess technically we're computing the paints more than we need to (we only need to compute them the first time, not when rect changes). Maybe add a TODO? Or not, your call. It's not a big deal.

Copy link
Contributor Author

@bernaferrari bernaferrari Aug 1, 2022

Choose a reason for hiding this comment

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

I need to test, but what if rotation, Transform, resize happens? Is it the same shadow?

Copy link
Contributor Author

@bernaferrari bernaferrari Aug 1, 2022

Choose a reason for hiding this comment

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

I'll try later (possibly tomorrow) but if we can get this working, optimization can be really big.

Copy link
Contributor

Choose a reason for hiding this comment

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

well the paint definitely isn't affected by the rect (it's computed by shadow.toPaint(), which doesn't get the rect). But the question is whether it's more expensive to compute the paint, or more expensive to handle the overhead of storing the paint in some other data structure in parallel with the rect bounds / paths. IIRC you had it the other way before and it was slower?

Copy link
Contributor Author

@bernaferrari bernaferrari Aug 1, 2022

Choose a reason for hiding this comment

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

I believe it was slower because of the additional loop, maybe the map, not exactly the additional structure. In this case, everything is going to be mostly similar. But I'll test, let's see.

Copy link
Contributor Author

@bernaferrari bernaferrari Aug 2, 2022

Choose a reason for hiding this comment

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

I have a proposal.

What if we had a mixin PrimitiveShape { paintInterior(...) } that is applied on RoundedRectangleBorder / CircleBorder / Stadium Border, then we do if (shape is PrimitiveShape) { (shape as PrimitiveShape).paintInterior(...) }?

We wouldn't need preferPaintInterior. And... maybe, one day, we could delimit the BorderSide.only/MultipleBorderSide (I still need to convince you) to only work on shapes that have that mixin. Is this too crazy?

We would solve a variable issue and a future documentation issue.

--

Alternate proposal: rename preferPaintInterior to isPrimitiveShape and explain the concept I just invented. But mixin sounds more fun.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Found what you said. Now I understand the issue. Testing a few things.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After debugging today: negligible difference, I'm reverting for the old way. Not changing what already works fine. My sample only uses a single color, if paint is complex enough, there might be differences.

Again, you are correct. Thanks!

Copy link
Contributor

@Hixie Hixie left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

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

LGTM

@goderbauer
Copy link
Member

@bernaferrari What is the status of this PR? It looks like the three last comments above may still be unresolved?

@bernaferrari
Copy link
Contributor Author

I traveled for the past few days, so couldn't find time to run some additional benchmarks to see if a variable was better or worse than a loop. I'll probably take a look tomorrow.

I also made a proposal to use a mixin instead of the hasPaintInside getter, but didn't get an answer.

Regardless, everything should be resolved on the next few days.

@bernaferrari bernaferrari force-pushed the Faster-ShapeDecoration branch from 9f8713e to 2eeddc2 Compare August 17, 2022 03:41
@bernaferrari
Copy link
Contributor Author

Sorry for the delay, here we go!! Fixed what needed to be fixed.

I rewrote this, if it is ok, feel free to add auto-submit. If it is not, let me know how I can improve. That's the last thing.

// For `ShapeDecoration(shape: Border.all())`, a rectangle with sharp edges
// is always painted. There is no BorderRadius parameter for
// ShapeDecoration or Border, only for BoxDecoration, which doesn't call
// this method.

@bernaferrari
Copy link
Contributor Author

I also made the snippet abstract so it compiles without implementing everything else, now that the snippet rules changed:
image

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

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

Changes reported for pull request #108648 at sha df7203d

@Hixie
Copy link
Contributor

Hixie commented Aug 17, 2022

I also made the snippet abstract so it compiles without implementing everything else

You don't need the abstract if you have the // ... bit (it adds an ignore for implementing abstract methods).

@bernaferrari
Copy link
Contributor Author

Thanks, I didn't know that.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

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

Changes reported for pull request #108648 at sha a58ad17

@Hixie
Copy link
Contributor

Hixie commented Aug 17, 2022

Thanks, I didn't know that.

Don't worry, you have no real way to have found out. It's documented in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying "Beware of the Leopard": https://github.com/flutter/flutter/blob/master/dev/bots/analyze_snippet_code.dart#L51

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

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

Changes reported for pull request #108648 at sha 6f0e420

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 c: contributor-productivity Team-specific productivity, code health, technical debt. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. will affect goldens Changes to golden files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants