Repository navigation
Description
Use case
This is the change proposed in #183817. That issue was closed before it answered the question asked there (why the existing external texture API isn't enough, and what the use cases are), so here is ours.
I'm porting Flutter to Sailfish OS, a Linux phone OS (Wayland, OpenGL ES, Android hardware drivers through libhybris), with a custom embedder on the embedder API (based on Sony's flutter-embedded-linux). For video_player, the phone's hardware decoder gives us each frame as an Android graphics buffer in a YUV format private to the vendor. The GPU can only sample those as an EGLImage bound to GL_TEXTURE_EXTERNAL_OES (GL_OES_EGL_image_external); they can't be bound to GL_TEXTURE_2D.
The existing API is enough: FlutterOpenGLTexture.target already says which target the texture is bound to. The engine's Skia path honours it (ResolveTextureSkia passes it to Skia in GrGLTextureInfo), so these textures already draw with Skia. ResolveTextureImpeller ignores it and always wraps the texture as kTexture2D, so under Impeller the same texture is sampled as a 2D texture, which an external image can't be. Impeller's GLES backend already supports kTextureExternalOES (Android's SurfaceTexture and ImageReader textures use it); the embedder path just never asks for it.
Alternatives:
- Pixel buffer textures, converting each frame to RGBA on the CPU and copying it. On a Jolla Phone 2026 playing a 1080x1920 H.264 video at 24 fps, the app uses about 71% of a CPU core that way, against 36% with the decoder's frames passed as external textures.
- Converting in the embedder, drawing each external texture into an RGBA
GL_TEXTURE_2Dfirst. That's an extra full-frame pass and texture for every frame, to do what Impeller can already do itself. - Vulkan isn't available: Sailfish OS apps have OpenGL ES only.
It isn't only Sailfish OS: flutter-tizen's embedder also passes its EGLImage textures with target = GL_TEXTURE_EXTERNAL_OES (external_texture_surface_egl.cc). As for the comment that closed #183817, the Windows and GTK Linux embedders pass GL_TEXTURE_2D, so this doesn't affect them. These textures come from embedders on OpenGL ES (embedded Linux, Tizen, Sailfish OS).
Proposal
In EmbedderExternalTextureGL::ResolveTextureImpeller (shell/platform/embedder/embedder_external_texture_gl.cc), describe the texture as external when the embedder says it is, as the Android external texture paths do:
impeller::TextureDescriptor desc;
desc.size = impeller::ISize(texture->width, texture->height);
desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
// An external texture (e.g. a video frame bound from an EGLImage) is
// sampled through samplerExternalOES, as on Android.
if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
desc.type = impeller::TextureType::kTextureExternalOES;
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
}Every other target keeps today's behaviour, so existing embedders aren't affected, and no API changes.
We ship this as a patch on Flutter 3.44 in our Sailfish OS port, where hardware-decoded video plays with both Impeller and Skia on a Jolla Phone 2026. Master's ResolveTextureImpeller still ignores the target. If this approach is OK, I'm happy to send a PR against master with an embedder unit test.
Activity
gaaclarke commentedon Nov 2, 2026
Yea, we'd be interested in that patch.
Support GL_TEXTURE_EXTERNAL_OES embedder textures in Impeller
robert-ancell commentedon Nov 3, 2026
I independently hit the same issue, and have a proposed fix in #195857.
Support GL_TEXTURE_EXTERNAL_OES embedder textures in Impeller (flutte…