Skip to content

[Impeller] Support rendering compressed texture formats / add capability to detect support. #148443

Open

Description

@jonahwilliams

I think that we could fairly easily add support for compressed image formats to Impeller, at least on the Vulkan and Metal backends.

Vulkan: https://docs.vulkan.org/spec/latest/appendices/compressedtex.html
iOS: https://developer.apple.com/documentation/metal/mtlpixelformat/mtlpixelformatastc_6x6_hdr?language=objc

I'm not sure what the actual level of device support is on Vulkan and would need to do some research. For iOS, there is a handy feature set table here: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf . We could look at the intersection of minimum supported formats as a starting point.

These formats specify how pixel data is compressed, but don't include header information on the format/size like commonly used network image formats like PNG/JPEG. This metadata would need to be provided by the application. I'm not sure if there are other standards here like ASTC in PNG or if the expectation is that the application level logic will handle transport compression/bundling.

For example, a low-level dart:ui API for decompressing.

import 'dart:ui' as uil
[
void main() {
  Uint8List data = getBytes(...);
  if (!ui.Codec.checkFormatSupport(PixelFormatASTC_4x4_sRGB)) { //Probably a different name
    return;
  }
  var ui.image = await ui.decodeCompressedTexture(data, width: 100, height: 100, format: VK_FORMAT_BC1_RGB_UNORM_BLOCK);
 

Then some higher level Image provider API:

Image.network(
  ...
  compressedFormat: CompressedFormat(PixelFormatASTC_4x4_sRGB, width: 100, height: 100)
 )

For testing/evaluating, there is an open source ASTC compressor developed by ARM available at https://github.com/ARM-software/astc-encoder.

Some caveats:

  • We can't support these in the Skia backend as the formats are unsupported as far as I know, unless we wrote separate import code and treated them as external textures (which I'd rather not do).
  • We currently resize images using Skia's software codecs which don't support these formats, so resizing would fail until we switch to GPU based resizing.

Activity

  1. chinmaygarde commented on May 16, 2024

    @chinmaygarde
    Contributor

    Exposing support for compressed texture formats as described is necessary, but I don't believe is sufficient in making a usable system. Especially given the myriad of formats that GPUs can natively support and the offline tooling necessary.

    I am in favor of one of the supercompressed formats in a standardized container like ktx2. In Dart code, the user can specify a file in a KTX2 container and we can do some minor conversion to a known supported format at runtime.

  2. chinmaygarde commented on May 16, 2024

    @chinmaygarde
    Contributor

    For reference, this is the guidance on Android. Also, Unity also does the transcoding like I described in an earlier comment. I am not sure if they use the open standard though. But from the perspective of an easy to use system, some sort of transcoding would be necessary.

  3. chinmaygarde commented on May 16, 2024

    @chinmaygarde
    Contributor

    More guidance on how other engines reason about a usable way to work with compressed textures. This also uses KTX2 for the container.

  4. jonahwilliams commented on May 16, 2024

    @jonahwilliams
    ContributorAuthor

    We don't need to build an end to end usable system though, that can be done as a package/community project. The only thing the community can't do is add engine support

  5. added
    P3Issues that are less important to the Flutter project
    c: new featureNothing broken; request for a new capability
    on May 20, 2024
  6. time4tea commented on Apr 28, 2025

    @time4tea

    It would be very interesting to be able to load compressed textures directly from KTX file, and to know which texture format would be preferred from a list of possibles - for example S3TC/DXT1...

  7. planetmarshall commented on Nov 17, 2025

    @planetmarshall
    Contributor

    As referenced above, we have proposed a design for compressed texture support in Flutter and have a limited but functional POC. The design document update is pending, in the meantime it can be viewed here (Google Docs)

  8. bdero commented on May 26, 2026

    @bdero
    Member

    Folding in design detail from #187072, which I filed as a duplicate of this issue and am now closing. The Flutter GPU surface work that depends on this is tracked in #187073.

    Suggested scope, grouped into three hardware families:

    • BC (S3TC, RGTC, BPTC): BC1 to BC7. Desktop GPUs.
    • ETC2 and EAC. Mobile, and any OpenGL ES 3.0 or WebGL2 context.
    • ASTC LDR. Modern mobile and some desktop.

    Skip these initially: PVRTC (deprecated, Apple only, being removed from WebGL), ETC1 (legacy, superseded by ETC2), ASTC HDR, and BC6H HDR. They can be added later behind the same query.

    Work items:

    1. Add the compressed PixelFormat values for the three families.
    2. Make descriptor math block-aware. Add bytes-per-block and block dimensions to formats.h, and update GetByteSizeOfBaseMipLevel and GetBytesPerRow to round to block extents.
    3. Add a compressed upload path: glCompressedTexSubImage2D (GLES), vkCmdCopyBufferToImage with block extents (Vulkan), and replaceRegion with compressed formats (Metal).
    4. Enforce usage restrictions: sample plus copy-destination only. No render target, no storage, no transient storage mode, and no runtime mip generation.
    5. Map the formats in each backend, gated by capability detection: Vulkan feature flags (textureCompressionBC, textureCompressionETC2, textureCompressionASTC_LDR), GLES extension strings, and Metal GPU family checks.

    Capability query API on impeller::Capabilities:

    enum class TextureCompressionType {
      kBC,    // Desktop. BC1 to BC7.
      kETC2,  // Mobile, GLES3, WebGL2.
      kASTC,  // Modern mobile, some desktop.
    };
    
    // True if the device supports a whole compressed family.
    virtual bool SupportsTextureCompression(TextureCompressionType type) const = 0;
    
    // Per-format, per-usage query. Covers compressed and uncompressed formats.
    virtual bool SupportsTextureFormat(PixelFormat format,
                                       TextureUsage usage) const = 0;

    SupportsTextureFormat is the general primitive. SupportsTextureCompression is a convenience for the common "can I use this family at all" check.

    No single compressed format works everywhere, which is why the query is required. Coverage is near-universal per tier: ETC2 and EAC are guaranteed on OpenGL ES 3.0 and WebGL2 and present on all mobile GPUs and Apple Silicon, BC is effectively guaranteed on desktop, and ASTC covers modern mobile. Together the three families cover essentially every target, and a single asset reaches all of them through KTX2 or Basis Universal transcoding at the asset layer, with uncompressed RGBA as the final fallback.

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

    P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilitye: impellerImpeller rendering backend issues and features requeststeam-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