Skip to content

Commit d6095e5

Browse files
[Impeller] Ensure that SnapshotControllerImpeller has a rendering context before creating the snapshot (flutter/engine#56743)
The Skia snapshot controller will activate the delegate's surface render context on the current thread. If the delegate has no surface, then it will use the snapshot surface producer to create a temporary surface. The Impeller snapshot controller needs to do the same in order to support OpenGL/GLES scenarios where the thread does not currently have an EGL context.
1 parent dee413e commit d6095e5

File tree

4 files changed

+86
-5
lines changed

4 files changed

+86
-5
lines changed

engine/src/flutter/shell/common/snapshot_controller_impeller.cc

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
namespace flutter {
1919

2020
namespace {
21+
2122
sk_sp<DlImage> DoMakeRasterSnapshot(
2223
const sk_sp<DisplayList>& display_list,
2324
SkISize size,
@@ -53,6 +54,27 @@ sk_sp<DlImage> DoMakeRasterSnapshot(
5354
DlImage::OwningContext::kRaster);
5455
}
5556

57+
sk_sp<DlImage> DoMakeRasterSnapshot(
58+
const sk_sp<DisplayList>& display_list,
59+
SkISize size,
60+
const SnapshotController::Delegate& delegate) {
61+
// Ensure that the current thread has a rendering context. This must be done
62+
// before calling GetAiksContext because constructing the AiksContext may
63+
// invoke graphics APIs.
64+
std::unique_ptr<Surface> pbuffer_surface;
65+
if (delegate.GetSurface()) {
66+
delegate.GetSurface()->MakeRenderContextCurrent();
67+
} else if (delegate.GetSnapshotSurfaceProducer()) {
68+
pbuffer_surface =
69+
delegate.GetSnapshotSurfaceProducer()->CreateSnapshotSurface();
70+
if (pbuffer_surface) {
71+
pbuffer_surface->MakeRenderContextCurrent();
72+
}
73+
}
74+
75+
return DoMakeRasterSnapshot(display_list, size, delegate.GetAiksContext());
76+
}
77+
5678
sk_sp<DlImage> DoMakeRasterSnapshot(
5779
sk_sp<DisplayList> display_list,
5880
SkISize picture_size,
@@ -112,16 +134,14 @@ void SnapshotControllerImpeller::MakeRasterSnapshot(
112134
}
113135
#endif
114136
callback(DoMakeRasterSnapshot(display_list, picture_size,
115-
GetDelegate().GetAiksContext()));
137+
GetDelegate()));
116138
}));
117139
}
118140

119141
sk_sp<DlImage> SnapshotControllerImpeller::MakeRasterSnapshotSync(
120142
sk_sp<DisplayList> display_list,
121143
SkISize picture_size) {
122-
return DoMakeRasterSnapshot(display_list, picture_size,
123-
GetDelegate().GetIsGpuDisabledSyncSwitch(),
124-
GetDelegate().GetAiksContext());
144+
return DoMakeRasterSnapshot(display_list, picture_size, GetDelegate());
125145
}
126146

127147
void SnapshotControllerImpeller::CacheRuntimeStage(

engine/src/flutter/shell/platform/android/android_surface_gl_impeller.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,24 @@ bool AndroidSurfaceGLImpeller::SetNativeWindow(
8181

8282
// |AndroidSurface|
8383
std::unique_ptr<Surface> AndroidSurfaceGLImpeller::CreateSnapshotSurface() {
84-
FML_UNREACHABLE();
84+
if (!onscreen_surface_ || !onscreen_surface_->IsValid()) {
85+
onscreen_surface_ = android_context_->CreateOffscreenSurface();
86+
if (!onscreen_surface_) {
87+
FML_DLOG(ERROR) << "Could not create offscreen surface for snapshot.";
88+
return nullptr;
89+
}
90+
}
91+
// Make the snapshot surface current because constucting a
92+
// GPUSurfaceGLImpeller and its AiksContext may invoke graphics APIs.
93+
if (!android_context_->OnscreenContextMakeCurrent(onscreen_surface_.get())) {
94+
FML_DLOG(ERROR) << "Could not make snapshot surface current.";
95+
return nullptr;
96+
}
97+
return std::make_unique<GPUSurfaceGLImpeller>(
98+
this, // delegate
99+
android_context_->GetImpellerContext(), // context
100+
true // render to surface
101+
);
85102
}
86103

87104
// |AndroidSurface|

engine/src/flutter/shell/platform/embedder/fixtures/main.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,3 +1595,20 @@ void render_impeller_text_test() {
15951595
};
15961596
PlatformDispatcher.instance.scheduleFrame();
15971597
}
1598+
1599+
@pragma('vm:entry-point')
1600+
// ignore: non_constant_identifier_names
1601+
Future<void> render_impeller_image_snapshot_test() async {
1602+
final PictureRecorder recorder = PictureRecorder();
1603+
final Canvas canvas = Canvas(recorder);
1604+
const Color color = Color.fromARGB(255, 0, 0, 123);
1605+
canvas.drawPaint(Paint()..color = color);
1606+
final Picture picture = recorder.endRecording();
1607+
1608+
final Image image = await picture.toImage(100, 100);
1609+
final ByteData? imageData = await image.toByteData();
1610+
final int pixel = imageData!.getInt32(0);
1611+
1612+
final bool result = (pixel & 0xFF) == color.alpha && ((pixel >> 8) & 0xFF) == color.blue;
1613+
notifyBoolValue(result);
1614+
}

engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4814,6 +4814,33 @@ TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
48144814
ASSERT_FALSE(present_called);
48154815
}
48164816

4817+
TEST_F(EmbedderTest, ImpellerOpenGLImageSnapshot) {
4818+
auto& context = GetEmbedderContext<EmbedderTestContextGL>();
4819+
4820+
bool result = false;
4821+
fml::AutoResetWaitableEvent latch;
4822+
context.AddNativeCallback("NotifyBoolValue",
4823+
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
4824+
result = tonic::DartConverter<bool>::FromDart(
4825+
Dart_GetNativeArgument(args, 0));
4826+
latch.Signal();
4827+
}));
4828+
4829+
EmbedderConfigBuilder builder(context);
4830+
builder.AddCommandLineArgument("--enable-impeller");
4831+
builder.SetDartEntrypoint("render_impeller_image_snapshot_test");
4832+
builder.SetSurface(SkISize::Make(800, 600));
4833+
builder.SetCompositor();
4834+
builder.SetRenderTargetType(
4835+
EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLFramebuffer);
4836+
4837+
auto engine = builder.LaunchEngine();
4838+
ASSERT_TRUE(engine.is_valid());
4839+
latch.Wait();
4840+
4841+
ASSERT_TRUE(result);
4842+
}
4843+
48174844
TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLSurface) {
48184845
auto& context = GetEmbedderContext<EmbedderTestContextGL>();
48194846

0 commit comments

Comments
 (0)