-
Notifications
You must be signed in to change notification settings - Fork 6k
Do not involve external_view_embedder in submit frame process if threads are not merged. #22275
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
| bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context, | ||
| std::shared_ptr<IOSContext> ios_context, | ||
| std::unique_ptr<SurfaceFrame> frame) { | ||
| if (views_to_dispose_.empty() && composition_order_.empty()) { |
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 won't fix the issue because composition_order_ is mutated by FlutterPlatformViewsController::PrerollCompositeEmbeddedView, PlatformViewLayer::Preroll (raster task queue), which still leaves the flutter_view_ race.
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 see, the thread merger check below is probably better.
shell/common/rasterizer.cc
Outdated
| return raster_status; | ||
| } | ||
| if (external_view_embedder != nullptr) { | ||
| if (external_view_embedder != nullptr && (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) { |
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.
Is raster_thread_merge_ thread-safe? raster_thread_merger_->Enable() is called from the platform thread.
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.
Looks like there are checks for raster_thread_merger_ being null on the platform thread while it is created on the raster thread, whilst not being atomic. That looks like a problem itself.
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.
raster_thread_merge_ is always on raster task runner. raster_thread_merger_->IsMerged() is thread safe.
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.
Looks like enabling the merger is protected by a mutex: https://github.com/gaaclarke/engine/blob/e1e90f2a2be3bbd61237cb794ec2e21ddfeace5e/fml/raster_thread_merger.cc#L101:L102
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.
we still need to address the flutter_view_ race, no?
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 @blasten is right about the race condition. Even with the threads merged we could end up in a SubmitFrame with a null flutter_view_ which the assert says shouldn't' happen. FWIW I ran the code with a null value for flutter_view_ by removing the assert and nothing crashed, so it looks like objc handled the null checks fine. We can just double check that null is handled fine and remove that assert maybe.
gaaclarke
left a comment
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 talked to @cyanglaz, I think this is a good fix. I'm going to run a bit of local testing just to make sure. LGTM assuming it passes automated and some manual testing.
shell/common/rasterizer.cc
Outdated
| // If raster_thread_merger_ is supported by the external_view_embedder, | ||
| // we make sure threads are merged before letting external_view_embedder | ||
| // to submit frame. Otherwise, fallback to `frame->Submit();` |
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 don't think the comment adds much to the code.
|
I have a 100% repro crash on a branch of the engine. When I rebased that branch onto this one, the crash doesn't happen anymore 👍 |
|
This is actually failing some tests that are counting number of calls for |
|
I tried to force the reproduction of the crash by delaying diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
index 7f593583a..59c14ff3d 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
@@ -923,6 +923,10 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
}
- (void)viewDidLayoutSubviews {
+ [self performSelector:@selector(viewDidLayoutSubviewsReal) withObject:nil afterDelay:5.0];
+}
+
+- (void)viewDidLayoutSubviewsReal {
CGRect viewBounds = self.view.bounds;
CGFloat scale = [UIScreen mainScreen].scale;This didn't crash because it appears the UI thread isn't presenting trees to be rendered. It is possible this crash is practically impossible to reproduce given the aggregate system. When looking at the rasterizer / platforms view controller we can see it's technically possible and it happens in my branch but my usage is atypical. |
blasten
left a comment
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. Assuming there's test for flutter_view_ = nullptr case + shell_unittest.cc changes.
|
Is the failure on the Mac iOS Engine presubmit related? |
|
Fixes flutter/flutter#69449 |
…ads are not merged.
shell/common/rasterizer_unittests.cc
Outdated
| /*device_pixel_ratio=*/2.0f); | ||
| bool result = pipeline->Produce().Complete(std::move(layer_tree)); | ||
| EXPECT_TRUE(result); | ||
| std::function<bool(LayerTree&)> no_discard = [](LayerTree&) { return false; }; |
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.
nit: this could just be auto no_discard
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.
done
| ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount()); | ||
|
|
||
| end_frame_latch.Wait(); | ||
| ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount()); |
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.
nit: is it possible to assert that threads are merged before this assert? Same where you have the comment // Threads not merged, can that be an assert?
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.
Done
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.
Actually, we can't assert if threads are not merged here, the threads are merged at the end of the frame. So it is actually merged here.
My comment was misleading, it should say that during the frame, the threads are not merged, they are merged at the end of the frame.
Updated the comment, PTAL
cyanglaz
left a comment
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.
@gaaclarke @blasten Updated with reviews, PTAL
shell/common/rasterizer_unittests.cc
Outdated
| .WillRepeatedly(Return(&external_view_embedder)); | ||
|
|
||
| auto surface_frame = std::make_unique<SurfaceFrame>( | ||
| nullptr, true, [](const SurfaceFrame&, SkCanvas*) { return true; }); |
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.
done
shell/common/rasterizer_unittests.cc
Outdated
| /*device_pixel_ratio=*/2.0f); | ||
| bool result = pipeline->Produce().Complete(std::move(layer_tree)); | ||
| EXPECT_TRUE(result); | ||
| std::function<bool(LayerTree&)> no_discard = [](LayerTree&) { return false; }; |
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.
done
shell/common/rasterizer_unittests.cc
Outdated
| EXPECT_CALL(external_view_embedder, BeginFrame).Times(1); | ||
| EXPECT_CALL(external_view_embedder, SubmitFrame).Times(1); | ||
| EXPECT_CALL(external_view_embedder, EndFrame).Times(1); |
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.
done
| ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount()); | ||
|
|
||
| end_frame_latch.Wait(); | ||
| ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount()); |
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.
Done
| ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount()); | ||
|
|
||
| end_frame_latch.Wait(); | ||
| ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount()); |
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.
Actually, we can't assert if threads are not merged here, the threads are merged at the end of the frame. So it is actually merged here.
My comment was misleading, it should say that during the frame, the threads are not merged, they are merged at the end of the frame.
Updated the comment, PTAL
| flutterPlatformViewsController->Reset(); | ||
| } | ||
|
|
||
| - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing { |
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.
Done!
| external_view_embedder->UpdatePostPrerollResult( | ||
| PostPrerollResult::kSuccess); | ||
| if (!raster_thread_merger_ref) { | ||
| raster_thread_merger_ref = raster_thread_merger; |
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 future improvements: this would be much easier if we were to create, and supply the thread merger in the test. Right now, this dependency is hardcoded in the rasterizer, which creates patterns like this.
blasten
left a comment
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
… if threads are not merged. (flutter/engine#22275)
… if threads are not merged. (flutter/engine#22275)
… if threads are not merged. (flutter/engine#22275)
… if threads are not merged. (flutter/engine#22275)
* Update 1.22 engine to use Dart 2.10.4 * [iOS TextInput] Avoid Unnecessary UndateEditingClient Calls (#21303) * added unit tests to the rasterizer (#22282) * Reland "Do not involve external_view_embedder in submit frame process if threads are not merged. #22275" (#22372) Co-authored-by: LongCatIsLooong <[email protected]> Co-authored-by: gaaclarke <[email protected]> Co-authored-by: Chris Yang <[email protected]>
…ads are not merged. (flutter#22275)
…tter#22348)" (flutter#22367) This reverts commit 0d5f2e9. Due to merge conflicts, this also reverts flutter#22275: Revert "Do not involve external_view_embedder in submit frame process if threads are not merged. (flutter#22275)" This reverts commit 016fbde.
… if threads are not merged. flutter#22275" (flutter#22372)
Alternatively, we can submit frame directly if threads aren't merged.
Fix flutter/flutter#69449
122f242 need to be cherry-picked before this commit can be cherry-picked. @zanderso
This PR also had conflicts with 0d5f2e9 and I had to rebase. Cherry-picking might be a little tricky