-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Add Rect::NormalizePoint method #47672
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, just switch to useing EXPECT
impeller/geometry/rect_unittests.cc
Outdated
ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) | ||
<< "Point(NaN x) in " << rect_desc << " Rect"; | ||
ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) | ||
<< "Point(NaN y) in " << rect_desc << " Rect"; | ||
ASSERT_EQ(Rect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) | ||
<< "Point(NaN x&y) in " << rect_desc << " Rect"; | ||
ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_x), Point()) | ||
<< "Point(NaN x) in " << rect_desc << " Rect"; | ||
ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_y), Point()) | ||
<< "Point(NaN y) in " << rect_desc << " Rect"; | ||
ASSERT_EQ(IRect::MakeLTRB(l, t, r, b).NormalizePoint(nan_p), Point()) | ||
<< "Point(NaN x&y) in " << rect_desc << " Rect"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should change this to EXPECT_EQ so the test always runs to completion. Probably all of them I'd have to double check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find a lot of inconsistency on that in the various tests. I can see your point about running to completion, but in the end all of the errors have to be fixed anyway and they are often due to the same mistake. So, is it spam or is it a full roster of errors?
I suppose given that none of these ASSERT statements can actually terminate the test (since they are inside local closures), EXPECT would be consistent with the fact that the test will complete its various calls to test() regardless of whether an individual call to test() terminates early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are strict about this internally and I ran into it the other day which reminded me not to sleep on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In doing a global replace I discovered that the NEAR
macros don't have EXPECT
equivalents. I'll file an issue so that we can apply the same logic to those kinds of tests...
(Filed: flutter/flutter#137873)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
googltest has EXPECT_NEAR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For single values, but the Impeller macros are for whole objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm! i'm curious if this autovectorizes.
I'm planning on switching to LTRB fields after all of this refactoring work which will change the implementation here. I'll run some experiments on godbolt when I do that to see how things vectorize. |
} | ||
} | ||
|
||
TEST(RectTest, NormalizePoint) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather see individual TEST cases versus a single case with a list of things it tests (you can pull up/re-use the test_one
closure I suppose). Basically any place you have to explain what different things are being tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are 630+ cases tested there. Do you want 630 TEST macros? If we require a TEST invocation for each and every condition tested we are incentivizing spot testing rather than rigorous testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just communicating I wouldn't understand what "failure: NormalizePoint line 969" means in a test log. Maybe that means a few (not 630, but not 3) test macros, and maybe it doesn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'm curious as to how much factorization you see being appropriate here. In the long view they are testing just a single Rect method. In the near view there's a lot of combinatorics and breaking up each combinatoric case would be unwieldy. But, maybe there is a slice in all of the cases that can be broken out? I'd want to avoid:
TEST(RectTest, NormalizePointWhereRectHasNaNXOriginAndPointHasInfiniteYOnRectAndIPoint) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just communicating I wouldn't understand what "failure: NormalizePoint line 969" means in a test log. Maybe that means a few (not 630, but not 3) test macros, and maybe it doesn't.
Which is why I use the labeling feature. The output contains the cases being tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought of a better way to use the labeling feature. Right now I'm using those strings to try to print out an "english description" of what the test case was, but perhaps I should just output Test Case: [I]Rect::MakeLTRB(<the values>).NormalizePoint([I]Point(<the values>)
? No need to explain that this is the "UL" or "Upper Left Corner of the Source Rectangle" - just let the values do the explaining...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, use this to run every test case so that the failures are self-documenting:
// Runs a single test case and outputs the parameters used on failure
// to make it easier to diagnose which test case failed.
auto test_case = [](Rect r, Point p, Point expected) {
EXPECT_EQ(r.NormalizePoint(p), expected)
<< "Rect" << r << ".NormalizePoint(Point" << p << ")";
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran with a variant of this using a macro that will perform the test and then print out the data on failure which helps identify which values are not compliant with the test/spec.
I didn't factor out the 2 cases any more than they had been, though, but they should be easier to read and the error output will be self-revealing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sabotaged one of the tests to get some error output to show what it looks like:
../../flutter/impeller/geometry/rect_unittests.cc:80: Failure
Expected equality of these values:
Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, px))
Which is: (1, 1)
expected
Which is: (1, 0)
Rect::MakeLTRB(100, 100, 200, 200).NormalizePoint(Point(200, 200))
../../flutter/impeller/geometry/rect_unittests.cc:80: Failure
Expected equality of these values:
Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, px))
Which is: (0, 0)
expected
Which is: (0, 1)
Rect::MakeLTRB(100, 100, 200, 200).NormalizePoint(Point(100, 100))
../../flutter/impeller/geometry/rect_unittests.cc:80: Failure
Expected equality of these values:
Rect::MakeLTRB(l, t, r, b).NormalizePoint(Point(px, px))
Which is: (2, 2)
expected
Which is: (2, -1)
Rect::MakeLTRB(100, 100, 200, 200).NormalizePoint(Point(300, 300))
impeller/geometry/rect.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add in the PR description what you imagine this being used for? Like even a link to a single existing method would be helpful to understand the context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of examples:
data[i + 1] = effect_transform * (points[j] - texture_coverage.origin) / |
data.texture_coords = effect_transform * |
I don't think these references make sense in the PR description as these are examples of "why" and the PR description, which gets copied into the final commit comment, should be more about the "what".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's hard for me to review a PR that will be used later without knowing for what.
The PR description (versus in the review) helps context for the next person "oh why did Jim add this method, oh its because of X").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used to normalize points. I believe it is appropriate to assume some familiarity with computer graphics and where normalization of points is used to review PRs for Impeller. I don't see how adding references in the description of the PR really enhances anything. The new method has an API comment to help explain what it does.
Should we explain which specific parts of the code would use Union
, Intersection
, Contains
when we add those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is reasonable to ask if the new methods will be used in a review, but I don't think the answer to that belongs in the PR description or the github commit comments. Those shouldn't be written to assuage suspicions of uselessness.
auto label is removed for flutter/engine/47672, due to This PR has not met approval requirements for merging. Changes were requested by {matanlurey}, please make the needed changes and resubmit this PR.
|
fb44c71
to
a112dfa
Compare
(TLDR - jedi hand wave - this may not be the method that we are looking for) @gaaclarke in reference to your comment about vectorization I was mulling the issue a bit over the weekend. At first I thought that it isn't likely to have a lot of impact because in the places this code is used, there isn't a tight loop around applying this method to some coordinates. Instead the loop always seems to contain at least a coordinate transform on the point in addition to the normalization, and in the case that is likely to see the most points applied in a single operation, the data is also being packed into a data structure for passing along. But then I realized that the normalization procedure itself is just a coordinate transform, equivalent to
and then use this |
Closing in favor of #47775 Will reopen/reconsider if we ever need to normalize coordinates while also not transforming them at the same time. |
Adds a utility method to perform work that is used in a number of locations within Impeller. Follow-on PRs will move those usages to the new utility methods in batches.