diff --git a/engine/src/flutter/shell/platform/embedder/BUILD.gn b/engine/src/flutter/shell/platform/embedder/BUILD.gn index de073b38654f6..18564dcaca528 100644 --- a/engine/src/flutter/shell/platform/embedder/BUILD.gn +++ b/engine/src/flutter/shell/platform/embedder/BUILD.gn @@ -254,6 +254,7 @@ test_fixtures("fixtures") { "fixtures/vk_dpr_noxform.png", "fixtures/vk_gradient.png", "fixtures/gradient_metal.png", + "fixtures/external_texture_impeller.png", "fixtures/external_texture_metal.png", "fixtures/gradient_xform.png", "fixtures/scene_without_custom_compositor.png", diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc index fe81731aff0d5..047617e479abc 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc @@ -138,13 +138,19 @@ sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( return nullptr; } + if (texture->format != GL_RGBA8) { + FML_LOG(ERROR) << "Only support GL_RGBA8 format now"; + return nullptr; + } + impeller::TextureDescriptor desc; desc.size = impeller::ISize(texture->width, texture->height); + desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt; impeller::ContextGLES& context = impeller::ContextGLES::Cast(*aiks_context->GetContext()); impeller::HandleGLES handle = context.GetReactor()->CreateHandle( - impeller::HandleType::kTexture, texture->target); + impeller::HandleType::kTexture, texture->name); std::shared_ptr image = impeller::TextureGLES::WrapTexture(context.GetReactor(), desc, handle); @@ -165,6 +171,8 @@ sk_sp EmbedderExternalTextureGL::ResolveTextureImpeller( FML_LOG(ERROR) << "Could not register destruction callback"; return nullptr; } + image->SetCoordinateSystem( + impeller::TextureCoordinateSystem::kUploadFromHost); return impeller::DlImageImpeller::Make(image); } diff --git a/engine/src/flutter/shell/platform/embedder/fixtures/external_texture_impeller.png b/engine/src/flutter/shell/platform/embedder/fixtures/external_texture_impeller.png new file mode 100644 index 0000000000000..0a6dfb6ec54b7 Binary files /dev/null and b/engine/src/flutter/shell/platform/embedder/fixtures/external_texture_impeller.png differ diff --git a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart index ea4f16371a5a9..bb9b2dababb55 100644 --- a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart @@ -1576,6 +1576,25 @@ void render_impeller_test() { PlatformDispatcher.instance.scheduleFrame(); } +@pragma('vm:entry-point') +// ignore: non_constant_identifier_names +void render_texture_impeller_test() { + PlatformDispatcher.instance.onBeginFrame = (Duration duration) { + const size = Size(800.0, 600.0); + + final builder = SceneBuilder(); + + builder.pushOffset(0.0, 0.0); + + builder.addTexture(/*textureId*/ 1, width: size.width, height: size.height); + + builder.pop(); + + PlatformDispatcher.instance.views.first.render(builder.build()); + }; + PlatformDispatcher.instance.scheduleFrame(); +} + @pragma('vm:entry-point') // ignore: non_constant_identifier_names void render_impeller_text_test() { diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc index e9711f53d871f..362d825985ab1 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc @@ -4829,6 +4829,87 @@ TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) { ASSERT_FALSE(present_called); } +TEST_F(EmbedderTest, RenderTextureWithImpellerOpenGL) { + auto& context = GetEmbedderContext(); + EmbedderConfigBuilder builder(context); + fml::AutoResetWaitableEvent latch; + bool present_called = false; + context.SetGLPresentCallback([&](FlutterPresentInfo present_info) { + present_called = true; + latch.Signal(); + }); + builder.AddCommandLineArgument("--enable-impeller"); + builder.SetDartEntrypoint("render_texture_impeller_test"); + builder.SetSurface(DlISize(800, 600)); + typedef void (*glGenTexturesProc)(GLsizei n, GLuint* textures); + typedef void (*glBindTextureProc)(GLenum n, GLuint texture); + typedef void (*glTexImage2DProc)(GLenum target, GLint level, + GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, + GLenum type, const void* pixels); + static glGenTexturesProc glGenTextures = reinterpret_cast( + context.GLGetProcAddress("glGenTextures")); + static glBindTextureProc glBindTexture = reinterpret_cast( + context.GLGetProcAddress("glBindTexture")); + static glTexImage2DProc glTexImage2D = reinterpret_cast( + context.GLGetProcAddress("glTexImage2D")); + + auto rendered_scene = context.GetNextSceneImage(); + context.GetRendererConfig().open_gl.gl_external_texture_frame_callback = + [](void* user_data, int64_t texture_id, size_t width, size_t height, + FlutterOpenGLTexture* texture) -> bool { + std::vector buffer(800 * 600 * 4); + for (int i = 0; i < 800 * 300; ++i) { + buffer[i * 4 + 0] = 255; // Red channel + buffer[i * 4 + 1] = 0; // Green channel + buffer[i * 4 + 2] = 0; // Blue channel + buffer[i * 4 + 3] = 255; // Alpha channel (fully opaque) + } + + for (int i = 800 * 300; i < 800 * 600; ++i) { + buffer[i * 4 + 0] = 0; // Red channel + buffer[i * 4 + 1] = 0; // Green channel + buffer[i * 4 + 2] = 255; // Blue channel + buffer[i * 4 + 3] = 255; // Alpha channel (fully opaque) + } + + GLuint gl_texture; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 800, 600, 0, GL_RGBA, + GL_UNSIGNED_BYTE, buffer.data()); + texture->target = GL_TEXTURE_2D; + texture->name = gl_texture; + texture->format = GL_RGBA8; + texture->destruction_callback = nullptr; + texture->user_data = nullptr; + texture->width = width; + texture->height = height; + return true; + }; + + auto engine = builder.LaunchEngine(); + + ASSERT_TRUE(engine.is_valid()); + + flutter::EmbedderEngine* embedder_engine = ToEmbedderEngine(engine.get()); + + ASSERT_TRUE(embedder_engine->RegisterTexture(1)); + ASSERT_TRUE(embedder_engine->MarkTextureFrameAvailable(1)); + + // 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); + latch.Wait(); + ASSERT_TRUE( + ImageMatchesFixture("external_texture_impeller.png", rendered_scene)); +} + TEST_F(EmbedderTest, ImpellerOpenGLImageSnapshot) { auto& context = GetEmbedderContext();