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

[DisplayList] DlPath supports generic path dispatching #164753

Merged
merged 8 commits into from
Mar 18, 2025

Conversation

flar
Copy link
Contributor

@flar flar commented Mar 7, 2025

There are different ways to iterate over an SkPath or an impeller::Path and various points in the engine source tree we have boilerplate duplicates of this code to transfer the contents of the DlPath wrapper object into some platform-specific path. This PR adds a dispatch/receiver mechanism to read back the contents of a DlPath - independent of whether it is backed by an SkPath or an impeller::Path - in a simpler form that avoids potential mistakes in the various conversion methods.

See DlPathReceiver and DlPath::Dispatch in the dl_path.h file

@github-actions github-actions bot added engine flutter/engine repository. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Mar 7, 2025
@flar flar marked this pull request as ready for review March 7, 2025 07:40
@flar flar requested a review from jonahwilliams March 7, 2025 07:40
@flar
Copy link
Contributor Author

flar commented Mar 7, 2025

I still have to change all of the path conversion methods sprinkled here and there to use the new mechanism.

Done. There were only 2 which seemed odd. I just went and looked at all of the code that handles clip mutators and noticed that most platforms either NOP a path clip or they just get the bounds and treat it like a clipRect. Well, at least now they have a simpler interface to deal with when we decide to add path support to the other platforms.

@github-actions github-actions bot added platform-android Android applications specifically platform-ios iOS applications specifically team-ios Owned by iOS platform team labels Mar 7, 2025
Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

I looked over the dispatching stuff, LGTM. I didn't do a full review since other people were looking at it before me. There isn't a test so this is just a refactor?

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

I looked over the dispatching stuff, LGTM. I didn't do a full review since other people were looking at it before me. There isn't a test so this is just a refactor?

Pretty much a refactor, and well covered by other tests, but it does introduce a new public method so there probably should be tests. I'll work on some.

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

Unit tests now added

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

This PR should be in its final state now.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

Okay I gave it a complete look. I have 2 suggestions which you are free to ignore and one that should get fixed, the argument comments are in the wrong format.

for (auto it = path.begin(), end = path.end(); it != end; ++it) {
switch (it.type()) {
case ComponentType::kContour: {
const impeller::ContourComponent* contour = it.contour();
FML_DCHECK(contour != nullptr);
if (subpath_needs_close) {
sk_path.close();
receiver.Close();
Copy link
Member

Choose a reason for hiding this comment

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

No action required: It's not in the c++ style guide but when calling virtual methods it's safer to use -> since if you accidentally get a value instead of a reference you'll get incorrect behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How? -> doesn't even compile.

Copy link
Member

Choose a reason for hiding this comment

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

You have to switch from using references to using pointers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would add the burden of implicitly accepting null values which must be checked. I don't understand the "value vs reference" issue and the incorrect behavior it leads to.

Copy link
Member

@gaaclarke gaaclarke Mar 10, 2025

Choose a reason for hiding this comment

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

When you have a reference in C++ it isn't guaranteed to not be null. You still technically have to consider null values, we just are ignoring that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a big TIL. I see so many comments here and there that references cannot ever be null, but I'm guessing you can fudge it with *pointer_that_is_null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps clang-tidy might complain (if it is run)?

Copy link
Member

Choose a reason for hiding this comment

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

but I'm guessing you can fudge it with *pointer_that_is_null?

Yep, exactly and we do this in our codebase all the time. A linter that disallowed references to anything on the heap would be nice, I don't think it exists. That's how I personally use them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll file this under "wishing C++ would throw if you create a reference by dereferencing a nulllptr".

const DlScalar weight;
};

class TestPathReceiver : public DlPathReceiver {
Copy link
Member

Choose a reason for hiding this comment

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

no action required: This class should just be a gmock.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I took a quick look at gmock just now, but it seems focused on just asserting that methods are called whereas this class is checking the data they are called with.

Copy link
Member

Choose a reason for hiding this comment

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

There are hundreds of examples of using gmock to check the arguments of function calls in our codebase. Here is one example:

This is asserting that AcquireFrame with arguments that equal frame_size.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand the formatting used there, it looks like it is placing expectations on return values, but my methods are all void and I'm placing expectations on the data they receive. Again, maybe that's in there, but I'd need to study gmock further - likely worth the work.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe this one is easier to see:

EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)).Times(1);

This is asserting that GenTextures is being called with 2 arguments, the first one must be 1 the second can be anything ("_" is a wildcard matcher).

I think this would be a good opportunity to learn how to use gmock. It's a very useful skill and I'm happy to help.

Copy link
Contributor Author

@flar flar Mar 10, 2025

Choose a reason for hiding this comment

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

There are so many similar classes I've written in the unit tests, time to look into that mechanism.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TIL-gmock. The tests are slightly more wordy, but the intent is outlined in the test itself and the mock receiver class was 100x simpler than the tester harness class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See also #165336

@flar
Copy link
Contributor Author

flar commented Mar 17, 2025

Bumped to ToT as it has been sitting for a week...

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

lgtm! you get your gmock merit badge 🧪

@flar flar requested a review from gaaclarke March 17, 2025 18:06
@flar flar added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 18, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Mar 18, 2025
Merged via the queue into flutter:master with commit c4d8870 Mar 18, 2025
171 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
e: impeller Impeller rendering backend issues and features requests engine flutter/engine repository. See also e: labels. platform-android Android applications specifically platform-ios iOS applications specifically team-ios Owned by iOS platform team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants