-
Notifications
You must be signed in to change notification settings - Fork 6k
Round SkRects in ClipRectContainsPlatformViewBoundingRect #50387
Conversation
634135f
to
a76625b
Compare
@@ -1529,6 +1538,8 @@ - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { | |||
XCTAssertLessThan( | |||
fabs(platformViewRectInFlutterView.size.height - childClippingView.frame.size.height), | |||
kFloatCompareEpsilon); | |||
|
|||
XCTAssertNil(childClippingView.maskView); |
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.
This check fails on master but passes on this PR.
a76625b
to
a2cc737
Compare
(@stuartmorgan I added you since you reviewed #37434 and maybe at one point were familiar with this code) |
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 think if you plan to work on platform view performance then it would be beneficial to have a benchmark running a non-trivial platform view. Eyeballing the cumulative effect of many small perf improvements will be difficult, and I've known many an engineer get discouraged when it felt like they weren't making progress.
return transformed_rect.contains(platformview_boundingrect); | ||
|
||
// Tolerate floating point errors when comparing flow clipping view bounds | ||
// and quartz platform view bounds. Round to integers. |
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.
Are these logical pixels or physical pixels? Integers seems pretty coarse.
Should we maybe outset the clip rect by a small delta instead?
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.
Physical pixels since it's running right before this logic:
engine/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Lines 562 to 567 in 45137ea
// The UIKit frame is set based on the logical resolution (points) instead of physical. | |
// (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html). | |
// However, flow is based on the physical resolution. For example, 1000 pixels in flow equals | |
// 500 points in UIKit for devices that has screenScale of 2. We need to scale the transformMatrix | |
// down to the logical resoltion before applying it to the layer of PlatformView. | |
transformMatrix.postScale(1 / screenScale, 1 / screenScale); |
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.
if its physical pixels and the error is at the scale of 0.00001, then even rounding to the nearest 0.01 should resolve the problem without having any meaningful effect on the rendering while still being way smaller than the space between two sample points (at 4x MSAA there are 4 per physical pixel).
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 should be fine to copy the logic here and round the outer rect out:
engine/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Lines 730 to 733 in 919af2c
for (SkIRect& joined_rect : intersection_rects) { | |
// Get the intersection rect between the current rect | |
// and the platform view rect. | |
joined_rect.intersect(platform_view_rect.roundOut()); |
/** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding
up fRight and fBottom, using
(sk_float_floor(fLeft), sk_float_floor(fTop),
sk_float_ceil(fRight), sk_float_ceil(fBottom)).
@param dst storage for SkRect
*/
void roundOut(SkRect* dst) const {
dst->setLTRB(sk_float_floor(fLeft), sk_float_floor(fTop),
sk_float_ceil(fRight), sk_float_ceil(fBottom));
}
For me to better understand - this rounding trick works because the platform view is less than 1 pixel outside the screen bound, and we mistakenly considered it as still within the screen bound (due to rounding errors)? |
@jmagman: @hellohuanlin has an open question. But otherwise this PR seems good to go. Can we land it? |
There's a request to make it round to 0.01 instead of integer. I need to update it. |
do we want to hold this till we have a project to measure the improvement? |
@@ -72,7 +71,6 @@ | |||
3DD7D38C27D2B81000DA365C /* FlutterUndoManagerPluginTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterUndoManagerPluginTest.mm; sourceTree = "<group>"; }; | |||
689EC1E2281B30D3008FEB58 /* FlutterSpellCheckPluginTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterSpellCheckPluginTest.mm; sourceTree = "<group>"; }; | |||
68B6091227F62F990036AC78 /* VsyncWaiterIosTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VsyncWaiterIosTest.mm; sourceTree = "<group>"; }; | |||
73F12C22288F92FF00AFC3A6 /* FlutterViewControllerTest_mrc.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest_mrc.mm; sourceTree = "<group>"; }; |
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.
Removed in #48162
@@ -50,7 +50,6 @@ | |||
0AC232F724BA71D300A85907 /* FlutterEngineTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEngineTest.mm; sourceTree = "<group>"; }; | |||
0AC2330324BA71D300A85907 /* accessibility_bridge_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = accessibility_bridge_test.mm; sourceTree = "<group>"; }; | |||
0AC2330B24BA71D300A85907 /* FlutterTextInputPluginTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterTextInputPluginTest.mm; sourceTree = "<group>"; }; | |||
0AC2330F24BA71D300A85907 /* FlutterBinaryMessengerRelayTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterBinaryMessengerRelayTest.mm; sourceTree = "<group>"; }; |
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.
FlutterBinaryMessengerRelayTest
is no longer in the iOS directory and is tested in common
#44395
Triage: The last update was that there was still some work to do to setup a benchmark for this. Is that still the case? |
This doesn't work except on top of #50386, which makes me think I don't have the whole picture here. Closing for now. |
Platform view clip mutators are being applied when the platform view scrolls off screen. This was due to floating point errors comparing the bounds of the platform view with the bounds of the clip view.
engine/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Lines 44 to 48 in 373b1ec
Example:
Clip rect:
Platform view rect:
The clip rect should be larger than the platform view rect and therefore no clipping should happen. The left and top should be equal, and the right and bottom clip is greater than the platform view. However, because the top 17.2308426 > 17.230835 the rect is not larger (for the clip rect to contain the platform view, left and top must be <= and right and bottom must be >=), then clipping happens, causing an expensive
-[FlutterClippingMaskView drawRect:]
call. Handle this by rounding the rect bounds during the fast-pathClipRectContainsPlatformViewBoundingRect
check.Fixes flutter/flutter#142828
See also #37434 and #20050
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.