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

Commit d1f3037

Browse files
author
Emmanuel Garcia
authored
Switch to FlutterSurfaceView if no Android view is in the frame (#19487)
1 parent 3620f2c commit d1f3037

File tree

10 files changed

+411
-70
lines changed

10 files changed

+411
-70
lines changed

shell/common/rasterizer.cc

+10-6
Original file line numberDiff line numberDiff line change
@@ -377,12 +377,6 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
377377
TRACE_EVENT0("flutter", "Rasterizer::DrawToSurface");
378378
FML_DCHECK(surface_);
379379

380-
auto frame = surface_->AcquireFrame(layer_tree.frame_size());
381-
382-
if (frame == nullptr) {
383-
return RasterStatus::kFailed;
384-
}
385-
386380
// There is no way for the compositor to know how long the layer tree
387381
// construction took. Fortunately, the layer tree does. Grab that time
388382
// for instrumentation.
@@ -398,6 +392,16 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
398392
embedder_root_canvas = external_view_embedder->GetRootCanvas();
399393
}
400394

395+
// On Android, the external view embedder deletes surfaces in `BeginFrame`.
396+
//
397+
// Deleting a surface also clears the GL context. Therefore, acquire the
398+
// frame after calling `BeginFrame` as this operation resets the GL context.
399+
auto frame = surface_->AcquireFrame(layer_tree.frame_size());
400+
401+
if (frame == nullptr) {
402+
return RasterStatus::kFailed;
403+
}
404+
401405
// If the external view embedder has specified an optional root surface, the
402406
// root surface transformation is set by the embedder instead of
403407
// having to apply it here.

shell/platform/android/external_view_embedder/external_view_embedder.cc

+25-9
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,20 @@ bool AndroidExternalViewEmbedder::SubmitFrame(
8585
std::unordered_map<int64_t, std::list<SkRect>> overlay_layers;
8686
std::unordered_map<int64_t, sk_sp<SkPicture>> pictures;
8787
SkCanvas* background_canvas = frame->SkiaCanvas();
88+
auto current_frame_view_count = composition_order_.size();
8889

8990
// Restore the clip context after exiting this method since it's changed
9091
// below.
9192
SkAutoCanvasRestore save(background_canvas, /*doSave=*/true);
9293

93-
for (size_t i = 0; i < composition_order_.size(); i++) {
94+
for (size_t i = 0; i < current_frame_view_count; i++) {
9495
int64_t view_id = composition_order_[i];
9596

9697
sk_sp<SkPicture> picture =
9798
picture_recorders_.at(view_id)->finishRecordingAsPicture();
9899
FML_CHECK(picture);
99100
pictures.insert({view_id, picture});
101+
100102
overlay_layers.insert({view_id, {}});
101103

102104
sk_sp<RTree> rtree = view_rtrees_.at(view_id);
@@ -142,8 +144,14 @@ bool AndroidExternalViewEmbedder::SubmitFrame(
142144
background_canvas->drawPicture(pictures.at(view_id));
143145
}
144146
// Submit the background canvas frame before switching the GL context to
145-
// the surfaces above.
146-
frame->Submit();
147+
// the overlay surfaces.
148+
//
149+
// Skip a frame if the embedding is switching surfaces.
150+
auto should_submit_current_frame =
151+
previous_frame_view_count_ > 0 || current_frame_view_count == 0;
152+
if (should_submit_current_frame) {
153+
frame->Submit();
154+
}
147155

148156
for (int64_t view_id : composition_order_) {
149157
SkRect view_rect = GetViewRect(view_id);
@@ -161,12 +169,15 @@ bool AndroidExternalViewEmbedder::SubmitFrame(
161169
params.mutatorsStack() //
162170
);
163171
for (const SkRect& overlay_rect : overlay_layers.at(view_id)) {
164-
CreateSurfaceIfNeeded(context, //
165-
view_id, //
166-
pictures.at(view_id), //
167-
overlay_rect //
168-
)
169-
->Submit();
172+
std::unique_ptr<SurfaceFrame> frame =
173+
CreateSurfaceIfNeeded(context, //
174+
view_id, //
175+
pictures.at(view_id), //
176+
overlay_rect //
177+
);
178+
if (should_submit_current_frame) {
179+
frame->Submit();
180+
}
170181
}
171182
}
172183
return true;
@@ -233,6 +244,8 @@ SkCanvas* AndroidExternalViewEmbedder::GetRootCanvas() {
233244
}
234245

235246
void AndroidExternalViewEmbedder::Reset() {
247+
previous_frame_view_count_ = composition_order_.size();
248+
236249
composition_order_.clear();
237250
picture_recorders_.clear();
238251
}
@@ -244,6 +257,9 @@ void AndroidExternalViewEmbedder::BeginFrame(
244257
double device_pixel_ratio,
245258
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
246259
Reset();
260+
261+
// The surface size changed. Therefore, destroy existing surfaces as
262+
// the existing surfaces in the pool can't be recycled.
247263
if (frame_size_ != frame_size) {
248264
surface_pool_->DestroyLayers(jni_facade_);
249265
}

shell/platform/android/external_view_embedder/external_view_embedder.h

+3
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
124124
// The r-tree that captures the operations for the picture recorders.
125125
std::unordered_map<int64_t, sk_sp<RTree>> view_rtrees_;
126126

127+
// The number of platform views in the previous frame.
128+
int64_t previous_frame_view_count_;
129+
127130
// Resets the state.
128131
void Reset();
129132

shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc

+120-15
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) {
250250
ASSERT_EQ(SkRect::MakeXYWH(75, 90, 105, 120), embedder->GetViewRect(view_id));
251251
}
252252

253-
TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
253+
TEST(AndroidExternalViewEmbedder, SubmitFrame) {
254254
auto jni_mock = std::make_shared<JNIMock>();
255255
auto android_context =
256256
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
@@ -294,6 +294,27 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
294294
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
295295

296296
// ------------------ First frame ------------------ //
297+
{
298+
auto did_submit_frame = false;
299+
auto surface_frame = std::make_unique<SurfaceFrame>(
300+
SkSurface::MakeNull(1000, 1000), false,
301+
[&did_submit_frame](const SurfaceFrame& surface_frame,
302+
SkCanvas* canvas) mutable {
303+
if (canvas != nullptr) {
304+
did_submit_frame = true;
305+
}
306+
return true;
307+
});
308+
309+
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
310+
// Submits frame if no Android view in the current frame.
311+
EXPECT_TRUE(did_submit_frame);
312+
313+
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
314+
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
315+
}
316+
317+
// ------------------ Second frame ------------------ //
297318
{
298319
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
299320
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
@@ -338,18 +359,26 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
338359
EXPECT_CALL(*jni_mock,
339360
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
340361

341-
auto surface_frame =
342-
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
343-
[](const SurfaceFrame& surface_frame,
344-
SkCanvas* canvas) { return true; });
362+
auto did_submit_frame = false;
363+
auto surface_frame = std::make_unique<SurfaceFrame>(
364+
SkSurface::MakeNull(1000, 1000), false,
365+
[&did_submit_frame](const SurfaceFrame& surface_frame,
366+
SkCanvas* canvas) mutable {
367+
if (canvas != nullptr) {
368+
did_submit_frame = true;
369+
}
370+
return true;
371+
});
345372

346373
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
374+
// Doesn't submit frame if there aren't Android views in the previous frame.
375+
EXPECT_FALSE(did_submit_frame);
347376

348377
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
349378
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
350379
}
351380

352-
// ------------------ Second frame ------------------ //
381+
// ------------------ Third frame ------------------ //
353382
{
354383
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
355384
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
@@ -392,11 +421,19 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
392421
EXPECT_CALL(*jni_mock,
393422
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
394423

395-
auto surface_frame =
396-
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
397-
[](const SurfaceFrame& surface_frame,
398-
SkCanvas* canvas) { return true; });
424+
auto did_submit_frame = false;
425+
auto surface_frame = std::make_unique<SurfaceFrame>(
426+
SkSurface::MakeNull(1000, 1000), false,
427+
[&did_submit_frame](const SurfaceFrame& surface_frame,
428+
SkCanvas* canvas) mutable {
429+
if (canvas != nullptr) {
430+
did_submit_frame = true;
431+
}
432+
return true;
433+
});
399434
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
435+
// Submits frame if there are Android views in the previous frame.
436+
EXPECT_TRUE(did_submit_frame);
400437

401438
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
402439
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@@ -423,15 +460,83 @@ TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) {
423460

424461
TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
425462
auto jni_mock = std::make_shared<JNIMock>();
426-
auto embedder =
427-
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
463+
auto android_context =
464+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
428465

466+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
467+
auto gr_context = GrContext::MakeMock(nullptr);
468+
auto frame_size = SkISize::Make(1000, 1000);
469+
auto surface_factory =
470+
[gr_context, window, frame_size](
471+
std::shared_ptr<AndroidContext> android_context,
472+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
473+
auto surface_frame_1 = std::make_unique<SurfaceFrame>(
474+
SkSurface::MakeNull(1000, 1000), false,
475+
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
476+
return true;
477+
});
478+
479+
auto surface_mock = std::make_unique<SurfaceMock>();
480+
EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
481+
.WillOnce(Return(ByMove(std::move(surface_frame_1))));
482+
483+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
484+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
485+
486+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
487+
.WillOnce(Return(ByMove(std::move(surface_mock))));
488+
489+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
490+
491+
return android_surface_mock;
492+
};
493+
494+
auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
495+
android_context, jni_mock, surface_factory);
429496
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
430-
ASSERT_FALSE(raster_thread_merger->IsMerged());
431497

432-
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
433-
raster_thread_merger);
498+
// ------------------ First frame ------------------ //
499+
{
500+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
501+
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
502+
503+
// Add an Android view.
504+
MutatorsStack stack1;
505+
// TODO(egarciad): Investigate why Flow applies the device pixel ratio to
506+
// the offsetPixels, but not the sizePoints.
507+
auto view_params_1 = std::make_unique<EmbeddedViewParams>(
508+
SkMatrix(), SkSize::Make(200, 200), stack1);
509+
510+
embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
511+
512+
// This simulates Flutter UI that intersects with the Android view.
513+
embedder->CompositeEmbeddedView(0)->drawRect(
514+
SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
515+
516+
// Create a new overlay surface.
517+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
518+
.WillOnce(Return(
519+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
520+
0, window))));
521+
// The JNI call to display the Android view.
522+
EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
523+
300, 300, stack1));
524+
EXPECT_CALL(*jni_mock,
525+
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
526+
527+
auto surface_frame =
528+
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
529+
[](const SurfaceFrame& surface_frame,
530+
SkCanvas* canvas) { return true; });
531+
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
532+
533+
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
534+
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
535+
}
536+
434537
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
538+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
539+
// Change the frame size.
435540
embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
436541
raster_thread_merger);
437542
}

shell/platform/android/external_view_embedder/surface_pool.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ void SurfacePool::RecycleLayers() {
7272

7373
void SurfacePool::DestroyLayers(
7474
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
75+
if (layers_.size() > 0) {
76+
jni_facade->FlutterViewDestroyOverlaySurfaces();
77+
}
7578
layers_.clear();
7679
available_layer_index_ = 0;
77-
jni_facade->FlutterViewDestroyOverlaySurfaces();
7880
}
7981

8082
std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {

shell/platform/android/external_view_embedder/surface_pool_unittests.cc

+36
Original file line numberDiff line numberDiff line change
@@ -164,5 +164,41 @@ TEST(SurfacePool, GetLayer__AllocateTwoLayers) {
164164
ASSERT_EQ(1, layer_2->id);
165165
}
166166

167+
TEST(SurfacePool, DestroyLayers) {
168+
auto pool = std::make_unique<SurfacePool>();
169+
auto jni_mock = std::make_shared<JNIMock>();
170+
171+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
172+
pool->DestroyLayers(jni_mock);
173+
174+
auto gr_context = GrContext::MakeMock(nullptr);
175+
auto android_context =
176+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
177+
178+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
179+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
180+
.Times(1)
181+
.WillOnce(Return(
182+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
183+
0, window))));
184+
185+
auto surface_factory =
186+
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
187+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
188+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
189+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
190+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
191+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
192+
return android_surface_mock;
193+
};
194+
pool->GetLayer(gr_context.get(), android_context, jni_mock, surface_factory);
195+
196+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
197+
pool->DestroyLayers(jni_mock);
198+
199+
pool->RecycleLayers();
200+
ASSERT_TRUE(pool->GetUnusedLayers().empty());
201+
}
202+
167203
} // namespace testing
168204
} // namespace flutter

0 commit comments

Comments
 (0)