diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index 57c37437405..cc9028f6a72 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -469,9 +469,6 @@ static sk_sp MakeSkSurfaceFromBackingStore( if (!surface) { FML_LOG(ERROR) << "Could not wrap embedder supplied render texture."; - if (texture->destruction_callback) { - texture->destruction_callback(texture->user_data); - } return nullptr; } @@ -514,9 +511,6 @@ static sk_sp MakeSkSurfaceFromBackingStore( if (!surface) { FML_LOG(ERROR) << "Could not wrap embedder supplied frame-buffer."; - if (framebuffer->destruction_callback) { - framebuffer->destruction_callback(framebuffer->user_data); - } return nullptr; } return surface; diff --git a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart index 07451592883..aa9114705fe 100644 --- a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart @@ -920,3 +920,20 @@ void snapshot_large_scene(int max_size) async { snapshotsCallback(big_image, small_image); } + +@pragma('vm:entry-point') +void invalid_backingstore() { + PlatformDispatcher.instance.onBeginFrame = (Duration duration) { + Color red = Color.fromARGB(127, 255, 0, 0); + Size size = Size(50.0, 150.0); + SceneBuilder builder = SceneBuilder(); + builder.pushOffset(0.0, 0.0); + builder.addPicture(Offset(10.0, 10.0), CreateColoredBox(red, size)); // red - flutter + builder.pop(); + PlatformDispatcher.instance.views.first.render(builder.build()); + }; + PlatformDispatcher.instance.onDrawFrame = () { + signalNativeTest(); + }; + PlatformDispatcher.instance.scheduleFrame(); +} diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc index 7a5f4750b16..35d8f26096f 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -3495,5 +3495,127 @@ TEST_F(EmbedderTest, ObjectsPostedViaPortsServicedOnSecondaryTaskHeap) { } } +TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetCompositor(); + builder.SetRenderTargetType( + EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLTexture); + builder.SetDartEntrypoint("invalid_backingstore"); + + class TestCollectOnce { + public: + // Collect() should only be called once + void Collect() { + ASSERT_FALSE(collected_); + collected_ = true; + } + + private: + bool collected_ = false; + }; + fml::AutoResetWaitableEvent latch; + + builder.GetCompositor().create_backing_store_callback = + [](const FlutterBackingStoreConfig* config, // + FlutterBackingStore* backing_store_out, // + void* user_data // + ) { + backing_store_out->type = kFlutterBackingStoreTypeOpenGL; + // Deliberately set this to be invalid + backing_store_out->user_data = nullptr; + backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeTexture; + backing_store_out->open_gl.texture.target = 0; + backing_store_out->open_gl.texture.name = 0; + backing_store_out->open_gl.texture.format = 0; + backing_store_out->open_gl.texture.user_data = new TestCollectOnce(); + backing_store_out->open_gl.texture.destruction_callback = + [](void* user_data) { + reinterpret_cast(user_data)->Collect(); + }; + return true; + }; + + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&latch](Dart_NativeArguments args) { latch.Signal(); })); + + auto engine = builder.LaunchEngine(); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + ASSERT_TRUE(engine.is_valid()); + latch.Wait(); +} + +TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetCompositor(); + builder.SetRenderTargetType( + EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLFramebuffer); + builder.SetDartEntrypoint("invalid_backingstore"); + + class TestCollectOnce { + public: + // Collect() should only be called once + void Collect() { + ASSERT_FALSE(collected_); + collected_ = true; + } + + private: + bool collected_ = false; + }; + fml::AutoResetWaitableEvent latch; + + builder.GetCompositor().create_backing_store_callback = + [](const FlutterBackingStoreConfig* config, // + FlutterBackingStore* backing_store_out, // + void* user_data // + ) { + backing_store_out->type = kFlutterBackingStoreTypeOpenGL; + // Deliberately set this to be invalid + backing_store_out->user_data = nullptr; + backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + backing_store_out->open_gl.framebuffer.target = 0; + backing_store_out->open_gl.framebuffer.name = 0; + backing_store_out->open_gl.framebuffer.user_data = + new TestCollectOnce(); + backing_store_out->open_gl.framebuffer.destruction_callback = + [](void* user_data) { + reinterpret_cast(user_data)->Collect(); + }; + return true; + }; + + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&latch](Dart_NativeArguments args) { latch.Signal(); })); + + auto engine = builder.LaunchEngine(); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + ASSERT_TRUE(engine.is_valid()); + latch.Wait(); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_metal.mm b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_metal.mm index 7f3a5ff1d38..522ddb84264 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_metal.mm +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_metal.mm @@ -379,5 +379,60 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) { ASSERT_TRUE(ImageMatchesFixture("compositor.png", scene_image)); } +TEST_F(EmbedderTest, CreateInvalidBackingstoreMetalTexture) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kMetalContext); + EmbedderConfigBuilder builder(context); + builder.SetMetalRendererConfig(SkISize::Make(800, 600)); + builder.SetCompositor(); + builder.SetRenderTargetType(EmbedderTestBackingStoreProducer::RenderTargetType::kMetalTexture); + builder.SetDartEntrypoint("invalid_backingstore"); + + class TestCollectOnce { + public: + // Collect() should only be called once + void Collect() { + ASSERT_FALSE(collected_); + collected_ = true; + } + + private: + bool collected_ = false; + }; + fml::AutoResetWaitableEvent latch; + + builder.GetCompositor().create_backing_store_callback = + [](const FlutterBackingStoreConfig* config, // + FlutterBackingStore* backing_store_out, // + void* user_data // + ) { + backing_store_out->type = kFlutterBackingStoreTypeMetal; + // Deliberately set this to be invalid + backing_store_out->user_data = nullptr; + backing_store_out->metal.texture.texture = 0; + backing_store_out->metal.struct_size = sizeof(FlutterMetalBackingStore); + backing_store_out->metal.texture.user_data = new TestCollectOnce(); + backing_store_out->metal.texture.destruction_callback = [](void* user_data) { + reinterpret_cast(user_data)->Collect(); + }; + return true; + }; + + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY([&latch](Dart_NativeArguments args) { latch.Signal(); })); + + auto engine = builder.LaunchEngine(); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), kSuccess); + ASSERT_TRUE(engine.is_valid()); + latch.Wait(); +} + } // namespace testing } // namespace flutter