From 55356b62bb113367c58c7faea7f36454c13690e3 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Fri, 2 Dec 2022 18:24:55 -0800 Subject: [PATCH] Add destruction test --- shell/platform/embedder/fixtures/main.dart | 32 +++++++++++++ .../tests/embedder_test_context_metal.cc | 14 +++++- .../tests/embedder_test_context_metal.h | 10 ++++ .../tests/embedder_unittests_metal.mm | 46 +++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 1726c5637389b..fecfa1ad12b3f 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -498,6 +498,38 @@ void can_composite_platform_views_with_platform_layer_on_bottom() { PlatformDispatcher.instance.scheduleFrame(); } +@pragma('vm:external-name', 'SignalBeginFrame') +external void signalBeginFrame(); + +@pragma('vm:entry-point') +void texture_destruction_callback_called_without_custom_compositor() async { + 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()); + }; + + // Schedule first frame. + final Completer firstFrame = Completer(); + PlatformDispatcher.instance.onDrawFrame = () { firstFrame.complete(); }; + PlatformDispatcher.instance.scheduleFrame(); + await firstFrame.future; + + // Schedule second frame to trigger disposal of first surface. + final Completer secondFrame = Completer(); + PlatformDispatcher.instance.onDrawFrame = () { secondFrame.complete(); }; + PlatformDispatcher.instance.scheduleFrame(); + await secondFrame.future; + + signalNativeTest(); +} + + @pragma('vm:entry-point') void can_render_scene_without_custom_compositor() { PlatformDispatcher.instance.onBeginFrame = (Duration duration) { diff --git a/shell/platform/embedder/tests/embedder_test_context_metal.cc b/shell/platform/embedder/tests/embedder_test_context_metal.cc index c649227b54800..a4f8e8604fc5e 100644 --- a/shell/platform/embedder/tests/embedder_test_context_metal.cc +++ b/shell/platform/embedder/tests/embedder_test_context_metal.cc @@ -71,10 +71,22 @@ bool EmbedderTestContextMetal::PopulateExternalTexture( } } +TestMetalContext::TextureInfo EmbedderTestContextMetal::GetTextureInfo() { + return metal_surface_->GetTextureInfo(); +} + +void EmbedderTestContextMetal::SetNextDrawableCallback( + NextDrawableCallback next_drawable_callback) { + next_drawable_callback_ = next_drawable_callback; +} + FlutterMetalTexture EmbedderTestContextMetal::GetNextDrawable( const FlutterFrameInfo* frame_info) { - auto texture_info = metal_surface_->GetTextureInfo(); + if (next_drawable_callback_ != nullptr) { + return next_drawable_callback_(frame_info); + } + auto texture_info = metal_surface_->GetTextureInfo(); FlutterMetalTexture texture; texture.struct_size = sizeof(FlutterMetalTexture); texture.texture_id = texture_info.texture_id; diff --git a/shell/platform/embedder/tests/embedder_test_context_metal.h b/shell/platform/embedder/tests/embedder_test_context_metal.h index eae23eb252d7e..d4b5914e9ae01 100644 --- a/shell/platform/embedder/tests/embedder_test_context_metal.h +++ b/shell/platform/embedder/tests/embedder_test_context_metal.h @@ -20,6 +20,9 @@ class EmbedderTestContextMetal : public EmbedderTestContext { size_t h, FlutterMetalExternalTexture* output)>; + using NextDrawableCallback = + std::function; + explicit EmbedderTestContextMetal(std::string assets_path = ""); ~EmbedderTestContextMetal() override; @@ -45,6 +48,12 @@ class EmbedderTestContextMetal : public EmbedderTestContext { TestMetalContext* GetTestMetalContext(); + // Returns the TextureInfo for the test Metal surface. + TestMetalContext::TextureInfo GetTextureInfo(); + + // Override the default handling for GetNextDrawable. + void SetNextDrawableCallback(NextDrawableCallback next_drawable_callback); + FlutterMetalTexture GetNextDrawable(const FlutterFrameInfo* frame_info); private: @@ -56,6 +65,7 @@ class EmbedderTestContextMetal : public EmbedderTestContext { std::unique_ptr metal_context_; std::unique_ptr metal_surface_; size_t present_count_ = 0; + NextDrawableCallback next_drawable_callback_ = nullptr; void SetupSurface(SkISize surface_size) override; diff --git a/shell/platform/embedder/tests/embedder_unittests_metal.mm b/shell/platform/embedder/tests/embedder_unittests_metal.mm index 296edf7b5723e..51126862f9c1c 100644 --- a/shell/platform/embedder/tests/embedder_unittests_metal.mm +++ b/shell/platform/embedder/tests/embedder_unittests_metal.mm @@ -227,6 +227,52 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), Gr ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png", rendered_scene)); } +TEST_F(EmbedderTest, TextureDestructionCallbackCalledWithoutCustomCompositorMetal) { + EmbedderTestContextMetal& context = reinterpret_cast( + GetEmbedderContext(EmbedderTestContextType::kMetalContext)); + EmbedderConfigBuilder builder(context); + builder.SetMetalRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("texture_destruction_callback_called_without_custom_compositor"); + + struct CollectContext { + bool collected = false; + }; + + auto collect_context = std::make_unique(); + context.SetNextDrawableCallback([&context, &collect_context](const FlutterFrameInfo* frame_info) { + auto texture_info = context.GetTextureInfo(); + FlutterMetalTexture texture; + texture.struct_size = sizeof(FlutterMetalTexture); + texture.texture_id = texture_info.texture_id; + texture.texture = reinterpret_cast(texture_info.texture); + texture.user_data = collect_context.get(); + texture.destruction_callback = [](void* user_data) { + CollectContext* callback_collect_context = reinterpret_cast(user_data); + callback_collect_context->collected = true; + }; + return texture; + }); + + fml::AutoResetWaitableEvent latch; + 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(); + EXPECT_TRUE(collect_context->collected); +} + TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) { auto& context = GetEmbedderContext(EmbedderTestContextType::kMetalContext);