Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e1a9d81

Browse files
author
Chris Yang
committed
Do not involve external_view_embedder in submit frame process if threads are not merged.
1 parent a8ec74f commit e1a9d81

File tree

4 files changed

+99
-29
lines changed

4 files changed

+99
-29
lines changed

shell/common/rasterizer.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,7 @@ void Rasterizer::Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline,
190190
consume_result = PipelineConsumeResult::MoreAvailable;
191191
}
192192

193-
// Merging the thread as we know the next `Draw` should be run on the platform
194-
// thread.
193+
// EndFrame should perform cleanups for the external_view_embedder.
195194
if (surface_ != nullptr && surface_->GetExternalViewEmbedder() != nullptr) {
196195
surface_->GetExternalViewEmbedder()->EndFrame(should_resubmit_frame,
197196
raster_thread_merger_);
@@ -469,7 +468,8 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
469468
raster_status == RasterStatus::kSkipAndRetry) {
470469
return raster_status;
471470
}
472-
if (external_view_embedder != nullptr) {
471+
if (external_view_embedder != nullptr &&
472+
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
473473
FML_DCHECK(!frame->IsSubmitted());
474474
external_view_embedder->SubmitFrame(surface_->GetContext(),
475475
std::move(frame));

shell/common/shell_unittests.cc

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,16 +1054,18 @@ TEST_F(ShellTest,
10541054
auto end_frame_callback =
10551055
[&](bool should_resubmit_frame,
10561056
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
1057-
external_view_embedder->UpdatePostPrerollResult(
1058-
PostPrerollResult::kSuccess);
1057+
if (should_resubmit_frame && !raster_thread_merger->IsMerged()) {
1058+
raster_thread_merger->MergeWithLease(10);
1059+
external_view_embedder->UpdatePostPrerollResult(
1060+
PostPrerollResult::kSuccess);
1061+
}
10591062
end_frame_latch.Signal();
10601063
};
10611064
external_view_embedder = std::make_shared<ShellTestExternalViewEmbedder>(
10621065
end_frame_callback, PostPrerollResult::kResubmitFrame, true);
10631066

10641067
auto shell = CreateShell(std::move(settings), GetTaskRunnersForFixture(),
10651068
false, external_view_embedder);
1066-
10671069
PlatformViewNotifyCreated(shell.get());
10681070

10691071
auto configuration = RunConfiguration::InferFromSettings(settings);
@@ -1074,12 +1076,16 @@ TEST_F(ShellTest,
10741076

10751077
PumpOneFrame(shell.get());
10761078
// `EndFrame` changed the post preroll result to `kSuccess`.
1079+
// First frame hasn't merged the threads yet, no
1080+
// `external_view_embedder->GetSubmittedFrameCount()` is called.
10771081
end_frame_latch.Wait();
1078-
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
1082+
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());
10791083

1084+
// This is the resubmitted frame, which threads are also merged.
10801085
end_frame_latch.Wait();
1081-
ASSERT_EQ(2, external_view_embedder->GetSubmittedFrameCount());
1086+
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
10821087

1088+
PlatformViewNotifyDestroyed(shell.get());
10831089
DestroyShell(std::move(shell));
10841090
}
10851091

@@ -2019,14 +2025,24 @@ TEST_F(ShellTest, DiscardLayerTreeOnResize) {
20192025
SkISize expected_size = SkISize::Make(400, 200);
20202026

20212027
fml::AutoResetWaitableEvent end_frame_latch;
2028+
std::shared_ptr<ShellTestExternalViewEmbedder> external_view_embedder;
2029+
auto end_frame_callback =
2030+
[&](bool should_merge_thread,
2031+
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
2032+
if (should_merge_thread) {
2033+
// TODO(cyanglaz): This test used external_view_embedder so we need to
2034+
// merge the threads here. However, the scenario it is testing is
2035+
// unrelated to platform views. We should consider to update this test
2036+
// so it doesn't require external_view_embedder.
2037+
raster_thread_merger->MergeWithLease(10);
2038+
external_view_embedder->UpdatePostPrerollResult(
2039+
PostPrerollResult::kSuccess);
2040+
}
2041+
end_frame_latch.Signal();
2042+
};
20222043

2023-
auto end_frame_callback = [&](bool, fml::RefPtr<fml::RasterThreadMerger>) {
2024-
end_frame_latch.Signal();
2025-
};
2026-
2027-
std::shared_ptr<ShellTestExternalViewEmbedder> external_view_embedder =
2028-
std::make_shared<ShellTestExternalViewEmbedder>(
2029-
std::move(end_frame_callback), PostPrerollResult::kSuccess, true);
2044+
external_view_embedder = std::make_shared<ShellTestExternalViewEmbedder>(
2045+
std::move(end_frame_callback), PostPrerollResult::kResubmitFrame, true);
20302046

20312047
std::unique_ptr<Shell> shell = CreateShell(
20322048
settings, GetTaskRunnersForFixture(), false, external_view_embedder);
@@ -2047,8 +2063,6 @@ TEST_F(ShellTest, DiscardLayerTreeOnResize) {
20472063

20482064
RunEngine(shell.get(), std::move(configuration));
20492065

2050-
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->GetEngine();
2051-
20522066
PumpOneFrame(shell.get(), static_cast<double>(wrong_size.width()),
20532067
static_cast<double>(wrong_size.height()));
20542068

@@ -2060,10 +2074,14 @@ TEST_F(ShellTest, DiscardLayerTreeOnResize) {
20602074
static_cast<double>(expected_size.height()));
20612075

20622076
end_frame_latch.Wait();
2077+
// Threads not merged.
2078+
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());
20632079

2080+
end_frame_latch.Wait();
20642081
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
20652082
ASSERT_EQ(expected_size, external_view_embedder->GetLastSubmittedFrameSize());
20662083

2084+
PlatformViewNotifyDestroyed(shell.get());
20672085
DestroyShell(std::move(shell));
20682086
}
20692087

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@
342342

343343
void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators_stack,
344344
UIView* embedded_view) {
345+
if (flutter_view_ == nullptr) {
346+
return;
347+
}
345348
FML_DCHECK(CATransform3DEqualToTransform(embedded_view.layer.transform, CATransform3DIdentity));
346349
ResetAnchor(embedded_view.layer);
347350
ChildClippingView* clipView = (ChildClippingView*)embedded_view.superview;
@@ -398,7 +401,6 @@
398401

399402
void FlutterPlatformViewsController::CompositeWithParams(int view_id,
400403
const EmbeddedViewParams& params) {
401-
FML_DCHECK(flutter_view_);
402404
CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
403405
UIView* touchInterceptor = touch_interceptors_[view_id].get();
404406
touchInterceptor.layer.transform = CATransform3DIdentity;
@@ -419,9 +421,8 @@
419421
}
420422

421423
SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) {
422-
FML_DCHECK(flutter_view_);
423-
// TODO(amirh): assert that this is running on the platform thread once we support the iOS
424-
// embedded views thread configuration.
424+
// Any UIKit related code has to run on main thread.
425+
FML_DCHECK([[NSThread currentThread] isMainThread]);
425426

426427
// Do nothing if the view doesn't need to be composited.
427428
if (views_to_recomposite_.count(view_id) == 0) {
@@ -469,12 +470,11 @@
469470
bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context,
470471
std::shared_ptr<IOSContext> ios_context,
471472
std::unique_ptr<SurfaceFrame> frame) {
472-
FML_DCHECK(flutter_view_);
473-
474473
// Any UIKit related code has to run on main thread.
475-
// When on a non-main thread, we only allow the rest of the method to run if there is no
476-
// Pending UIView operations.
477-
FML_DCHECK([[NSThread currentThread] isMainThread] || !HasPlatformViewThisOrNextFrame());
474+
FML_DCHECK([[NSThread currentThread] isMainThread]);
475+
if (flutter_view_ == nullptr) {
476+
return frame->Submit();
477+
}
478478

479479
DisposeViews();
480480

@@ -558,8 +558,6 @@
558558
BringLayersIntoView(platform_view_layers);
559559
// Mark all layers as available, so they can be used in the next frame.
560560
layer_pool_->RecycleLayers();
561-
// Reset the composition order, so next frame starts empty.
562-
composition_order_.clear();
563561

564562
did_submit &= frame->Submit();
565563

@@ -599,7 +597,10 @@
599597

600598
void FlutterPlatformViewsController::EndFrame(
601599
bool should_resubmit_frame,
602-
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {}
600+
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
601+
// Reset the composition order, so next frame starts empty.
602+
composition_order_.clear();
603+
}
603604

604605
std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
605606
GrDirectContext* gr_context,

shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,57 @@ - (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents {
602602
flutterPlatformViewsController->Reset();
603603
}
604604

605+
- (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing {
606+
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
607+
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
608+
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
609+
/*platform=*/thread_task_runner,
610+
/*raster=*/thread_task_runner,
611+
/*ui=*/thread_task_runner,
612+
/*io=*/thread_task_runner);
613+
auto surface_factory = flutter::IOSSurfaceFactory::Create(flutter::IOSRenderingAPI::kSoftware);
614+
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
615+
/*delegate=*/mock_delegate,
616+
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
617+
/*ios_surface_factory=*/surface_factory,
618+
/*task_runners=*/runners);
619+
620+
auto flutterPlatformViewsController =
621+
std::make_shared<flutter::FlutterPlatformViewsController>(surface_factory);
622+
surface_factory->SetPlatformViewsController(flutterPlatformViewsController);
623+
624+
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
625+
[[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
626+
flutterPlatformViewsController->RegisterViewFactory(
627+
factory, @"MockFlutterPlatformView",
628+
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
629+
FlutterResult result = ^(id result) {
630+
};
631+
flutterPlatformViewsController->OnMethodCall(
632+
[FlutterMethodCall
633+
methodCallWithMethodName:@"create"
634+
arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
635+
result);
636+
637+
XCTAssertNotNil(gMockPlatformView);
638+
639+
// Create embedded view params
640+
flutter::MutatorsStack stack;
641+
SkMatrix finalMatrix;
642+
643+
auto embeddedViewParams =
644+
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
645+
646+
flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
647+
flutterPlatformViewsController->CompositeEmbeddedView(2);
648+
auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
649+
nullptr, true,
650+
[](const flutter::SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; });
651+
flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface));
652+
653+
flutterPlatformViewsController->Reset();
654+
}
655+
605656
- (int)alphaOfPoint:(CGPoint)point onView:(UIView*)view {
606657
unsigned char pixel[4] = {0};
607658

0 commit comments

Comments
 (0)