[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.
This commit is contained in:
parent
dee413e427
commit
d6095e5be3
@ -18,6 +18,7 @@
|
|||||||
namespace flutter {
|
namespace flutter {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
sk_sp<DlImage> DoMakeRasterSnapshot(
|
sk_sp<DlImage> DoMakeRasterSnapshot(
|
||||||
const sk_sp<DisplayList>& display_list,
|
const sk_sp<DisplayList>& display_list,
|
||||||
SkISize size,
|
SkISize size,
|
||||||
@ -53,6 +54,27 @@ sk_sp<DlImage> DoMakeRasterSnapshot(
|
|||||||
DlImage::OwningContext::kRaster);
|
DlImage::OwningContext::kRaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk_sp<DlImage> DoMakeRasterSnapshot(
|
||||||
|
const sk_sp<DisplayList>& display_list,
|
||||||
|
SkISize size,
|
||||||
|
const SnapshotController::Delegate& delegate) {
|
||||||
|
// Ensure that the current thread has a rendering context. This must be done
|
||||||
|
// before calling GetAiksContext because constructing the AiksContext may
|
||||||
|
// invoke graphics APIs.
|
||||||
|
std::unique_ptr<Surface> pbuffer_surface;
|
||||||
|
if (delegate.GetSurface()) {
|
||||||
|
delegate.GetSurface()->MakeRenderContextCurrent();
|
||||||
|
} else if (delegate.GetSnapshotSurfaceProducer()) {
|
||||||
|
pbuffer_surface =
|
||||||
|
delegate.GetSnapshotSurfaceProducer()->CreateSnapshotSurface();
|
||||||
|
if (pbuffer_surface) {
|
||||||
|
pbuffer_surface->MakeRenderContextCurrent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoMakeRasterSnapshot(display_list, size, delegate.GetAiksContext());
|
||||||
|
}
|
||||||
|
|
||||||
sk_sp<DlImage> DoMakeRasterSnapshot(
|
sk_sp<DlImage> DoMakeRasterSnapshot(
|
||||||
sk_sp<DisplayList> display_list,
|
sk_sp<DisplayList> display_list,
|
||||||
SkISize picture_size,
|
SkISize picture_size,
|
||||||
@ -112,16 +134,14 @@ void SnapshotControllerImpeller::MakeRasterSnapshot(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
callback(DoMakeRasterSnapshot(display_list, picture_size,
|
callback(DoMakeRasterSnapshot(display_list, picture_size,
|
||||||
GetDelegate().GetAiksContext()));
|
GetDelegate()));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<DlImage> SnapshotControllerImpeller::MakeRasterSnapshotSync(
|
sk_sp<DlImage> SnapshotControllerImpeller::MakeRasterSnapshotSync(
|
||||||
sk_sp<DisplayList> display_list,
|
sk_sp<DisplayList> display_list,
|
||||||
SkISize picture_size) {
|
SkISize picture_size) {
|
||||||
return DoMakeRasterSnapshot(display_list, picture_size,
|
return DoMakeRasterSnapshot(display_list, picture_size, GetDelegate());
|
||||||
GetDelegate().GetIsGpuDisabledSyncSwitch(),
|
|
||||||
GetDelegate().GetAiksContext());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotControllerImpeller::CacheRuntimeStage(
|
void SnapshotControllerImpeller::CacheRuntimeStage(
|
||||||
|
@ -81,7 +81,24 @@ bool AndroidSurfaceGLImpeller::SetNativeWindow(
|
|||||||
|
|
||||||
// |AndroidSurface|
|
// |AndroidSurface|
|
||||||
std::unique_ptr<Surface> AndroidSurfaceGLImpeller::CreateSnapshotSurface() {
|
std::unique_ptr<Surface> AndroidSurfaceGLImpeller::CreateSnapshotSurface() {
|
||||||
FML_UNREACHABLE();
|
if (!onscreen_surface_ || !onscreen_surface_->IsValid()) {
|
||||||
|
onscreen_surface_ = android_context_->CreateOffscreenSurface();
|
||||||
|
if (!onscreen_surface_) {
|
||||||
|
FML_DLOG(ERROR) << "Could not create offscreen surface for snapshot.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make the snapshot surface current because constucting a
|
||||||
|
// GPUSurfaceGLImpeller and its AiksContext may invoke graphics APIs.
|
||||||
|
if (!android_context_->OnscreenContextMakeCurrent(onscreen_surface_.get())) {
|
||||||
|
FML_DLOG(ERROR) << "Could not make snapshot surface current.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::make_unique<GPUSurfaceGLImpeller>(
|
||||||
|
this, // delegate
|
||||||
|
android_context_->GetImpellerContext(), // context
|
||||||
|
true // render to surface
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// |AndroidSurface|
|
// |AndroidSurface|
|
||||||
|
@ -1595,3 +1595,20 @@ void render_impeller_text_test() {
|
|||||||
};
|
};
|
||||||
PlatformDispatcher.instance.scheduleFrame();
|
PlatformDispatcher.instance.scheduleFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
Future<void> render_impeller_image_snapshot_test() async {
|
||||||
|
final PictureRecorder recorder = PictureRecorder();
|
||||||
|
final Canvas canvas = Canvas(recorder);
|
||||||
|
const Color color = Color.fromARGB(255, 0, 0, 123);
|
||||||
|
canvas.drawPaint(Paint()..color = color);
|
||||||
|
final Picture picture = recorder.endRecording();
|
||||||
|
|
||||||
|
final Image image = await picture.toImage(100, 100);
|
||||||
|
final ByteData? imageData = await image.toByteData();
|
||||||
|
final int pixel = imageData!.getInt32(0);
|
||||||
|
|
||||||
|
final bool result = (pixel & 0xFF) == color.alpha && ((pixel >> 8) & 0xFF) == color.blue;
|
||||||
|
notifyBoolValue(result);
|
||||||
|
}
|
||||||
|
@ -4814,6 +4814,33 @@ TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
|
|||||||
ASSERT_FALSE(present_called);
|
ASSERT_FALSE(present_called);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(EmbedderTest, ImpellerOpenGLImageSnapshot) {
|
||||||
|
auto& context = GetEmbedderContext<EmbedderTestContextGL>();
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
fml::AutoResetWaitableEvent latch;
|
||||||
|
context.AddNativeCallback("NotifyBoolValue",
|
||||||
|
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
|
||||||
|
result = tonic::DartConverter<bool>::FromDart(
|
||||||
|
Dart_GetNativeArgument(args, 0));
|
||||||
|
latch.Signal();
|
||||||
|
}));
|
||||||
|
|
||||||
|
EmbedderConfigBuilder builder(context);
|
||||||
|
builder.AddCommandLineArgument("--enable-impeller");
|
||||||
|
builder.SetDartEntrypoint("render_impeller_image_snapshot_test");
|
||||||
|
builder.SetSurface(SkISize::Make(800, 600));
|
||||||
|
builder.SetCompositor();
|
||||||
|
builder.SetRenderTargetType(
|
||||||
|
EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLFramebuffer);
|
||||||
|
|
||||||
|
auto engine = builder.LaunchEngine();
|
||||||
|
ASSERT_TRUE(engine.is_valid());
|
||||||
|
latch.Wait();
|
||||||
|
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLSurface) {
|
TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLSurface) {
|
||||||
auto& context = GetEmbedderContext<EmbedderTestContextGL>();
|
auto& context = GetEmbedderContext<EmbedderTestContextGL>();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user