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] Add rounded superellipse #56726

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Conversation

dkwingsmt
Copy link
Contributor

@dkwingsmt dkwingsmt commented Nov 20, 2024

Support rounded superellipse.

Part of flutter/flutter#139321 and flutter/flutter#13914, also related to flutter/flutter#91523.

Open questions

  • Alternative names:
    • RoundedSuperellipse
    • Squircle
    • ContinuousBorderRectangle (or something like this...)
    • I chose rounded superellipse because this name, albeit its length, precisely describe this shape. "Squircle" is not strictly defined but generally refers any shape intermediate between a rectangle and a circle.
  • Alternative definition for corner_radius:
    • Currently the corner_radius corresponds to SwiftUI parameters. To make the shape definition more generalized, we can instead define the corner_radius to be the radius of the corner circles, and make the framework do a look up table.
    • The down side is, not only the work to re-calculate the table, but also that it doesn't completely eliminates the relationship with SwiftUI, since currently the degree of the superellipse (n) is also mapped from the SwiftUI cornerRadius, which is not necessary for the shape per se.
    • To some extent it boils down to the question of whether we'd like this shape to support anything beyond SwiftUI.

Demo

Screen.Recording.2024-11-21.at.5.26.56.PM.mp4

Low ratio: (900, 900, 445)

image

Mid ratio: (900, 650, 180)

image

High ratio: (900, 650, 17)

image

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@dkwingsmt dkwingsmt marked this pull request as ready for review November 22, 2024 01:57
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.

Really excited to see this work coming along!


// Points without applying `flip` and `center`.
std::vector<Point> points;
points.reserve(21);
Copy link
Member

Choose a reason for hiding this comment

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

What is this number from?

// Draw the first quadrant of the shape and store in `points`. It will be
// mirrored to other quadrants later.
std::vector<Point> points;
points.reserve(41);
Copy link
Member

Choose a reason for hiding this comment

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

same here, what is this number from?

std::vector<Point> points;
points.reserve(41);

DrawOctantSquareLikeSquircle(points, size.width, corner_radius_, Point{0, -c},
Copy link
Member

Choose a reason for hiding this comment

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

The tessellator has a large point area already allocated for temp workloads (ignore name): https://github.com/flutter/engine/blob/main/impeller/tessellator/tessellator.h#L310 . This has 4096 slots of storage. If you can handle overflows by writing to a temp buffer, then its going to be much faster to write there instead of to a newly created vector.


bool RoundSuperellipseGeometry::CoversArea(const Matrix& transform,
const Rect& rect) const {
return false;
Copy link
Member

Choose a reason for hiding this comment

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

I'd imagine computing a conservative inner rect for the rounded superellipse should be possible, no?

@jonahwilliams
Copy link
Member

I changed canvas.drawRect to use this geometry and then ran an app that draws a few dozen rectangles to get this profile. It looks like the vast majority of overhead is from temporary allocation. That should disappear if you use the preallocated arenas.

Also kAngleStep may be too small for small rectangles. I'm getting ~182 points for a 20x20 squircle. You may want to eyeball some numbers for this based off of the rectangle size.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants