Skip to content

[Impeller] Honour FlutterOpenGLTexture.target for GL_TEXTURE_EXTERNAL_OES in embedder external textures #195543

Closed

Description

@knasher

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_2D first. 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

  1. added
    in triagePresently being triaged by the triage team
    engineflutter/engine related. See also e: labels.
    platform-linuxBuilding on or for Linux specifically
    c: proposalA detailed proposal for a change to Flutter
    and removed
    in triagePresently being triaged by the triage team
    on Oct 29, 2026
  2. added
    P2Important issues not at the top of the work list
    on Nov 2, 2026
  3. gaaclarke commented on Nov 2, 2026

    @gaaclarke
    Member

    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.

    Yea, we'd be interested in that patch.

  4. robert-ancell commented on Nov 3, 2026

    @robert-ancell
    Contributor

    I independently hit the same issue, and have a proposed fix in #195857.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: proposalA detailed proposal for a change to Flutterengineflutter/engine related. See also e: labels.platform-linuxBuilding on or for Linux specificallyteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions