Skip to content

**[Impeller/Vulkan] Core texture compression features (ETC2/ASTC LDR/BC) are never enabled at device creation, so flutter_gpu reports no compressed texture support on all Android Vulkan devices** #189107

Closed

Description

@guszxtavo

Steps to reproduce

  1. Run any app using flutter_gpu on an Android device where Impeller selects the Vulkan backend (e.g. Samsung Galaxy A54 / Mali-G68 / Vulkan 1.3 — logcat shows Using the Impeller rendering backend (Vulkan).).
  2. Query compressed texture support:
import 'package:flutter_gpu/gpu.dart' as gpu;

final bc = gpu.gpuContext.supportsTextureCompression(gpu.TextureCompressionFamily.bc);
final etc2 = gpu.gpuContext.supportsTextureCompression(gpu.TextureCompressionFamily.etc2);
final astc = gpu.gpuContext.supportsTextureCompression(gpu.TextureCompressionFamily.astc);
// bc=false etc2=false astc=false — on hardware that fully supports ETC2 + ASTC

The same is observable through package:flutter_scene 0.18.x, whose KTX2 upload path logs:

flutter_scene texture compression support: bc=false etc2=false astc=false (transcode runs off the main isolate; rgba8 fallback otherwise)

Expected results

On a Vulkan 1.3 Android device with a Mali/Adreno GPU, etc2 should be true (mandatory in practice on mobile Vulkan implementations) and astc should be true where VkPhysicalDeviceFeatures::textureCompressionASTC_LDR is supported — matching what the GLES and Metal backends already report on equivalent hardware.

Actual results

All LDR compression families report false on every Android Vulkan device, regardless of hardware support. Compressed texture uploads are impossible on the flagship Android backend, forcing consumers (e.g. flutter_scene) to fall back to uncompressed RGBA8 (≈8× VRAM).

Regression range

This is a follow-up defect to the PR that added compressed-texture support, not a pre-existing limitation:

Net effect: the feature shipped functional on GLES and Metal, but dead-on-arrival on Android/Vulkan — the default backend on modern Android.

Root cause (from source)

CapabilitiesVK answers the query from the enabled device features:

engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc (@ 47215701bc6e, also present on current master):

// ~line 670
{
  const auto& features = enabled_features.get().features;
  supports_texture_compression_bc_ = features.textureCompressionBC;
  supports_texture_compression_etc2_ = features.textureCompressionETC2;
  supports_texture_compression_astc_ = features.textureCompressionASTC_LDR;
}

…but GetEnabledDeviceFeatures() never requests those core features when building the required_chain passed to vkCreateDevice. The "Base features" block only enables two features:

// ~line 446 ("Base features")
{
  auto& required = required_chain.get().features;
  const auto& supported = supported_chain.get().features;

  required.fillModeNonSolid = supported.fillModeNonSolid;
  required.samplerAnisotropy = supported.samplerAnisotropy;
}

textureCompressionETC2 / textureCompressionASTC_LDR / textureCompressionBC are absent, so they are never enabled, so the capability reads back false unconditionally. (Notably, ASTC HDR is wired — via VK_EXT_texture_compression_astc_hdr at ~line 502 — while the far more common LDR core features are not, which suggests an oversight rather than a policy.)

For comparison, the other two backends wire this correctly:

  • GLES — engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc (~line 186-202): ETC2 from IsES() && major >= 3, ASTC from GL_KHR/OES_texture_compression_astc* extensions.
  • Metal — engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm (~line 55-105): ETC2/ASTC on MTLGPUFamilyApple2+, ASTC HDR on Apple6+.

Vulkan on Android is therefore the only backend where block-compressed textures can never be used — and it is the default backend on modern Android devices.

Evidence from #187077's own diff

The introducing PR (#187077) makes the asymmetry unambiguous. In capabilities_vk.cc it added the read-back for all four families in SetPhysicalDevice:

+  {
+    const auto& features = enabled_features.get().features;
+    supports_texture_compression_bc_   = features.textureCompressionBC;
+    supports_texture_compression_etc2_ = features.textureCompressionETC2;
+    supports_texture_compression_astc_ = features.textureCompressionASTC_LDR;
+  }
+  supports_texture_compression_astc_hdr_ = /* ...from the HDR extension... */;

…but in GetEnabledDeviceFeatures the same PR wired the enable for only ASTC HDR:

+  // VK_EXT_texture_compression_astc_hdr
+  ...
+    required.textureCompressionASTC_HDR = supported.textureCompressionASTC_HDR;

No required.textureCompressionETC2 / ASTC_LDR / BC = supported.* line was added anywhere. So three of the four families are read back from features that are never requested — they can only ever be false. It is a three-line omission within the PR that added the feature, not a design decision.

Proposed fix

Mirror the existing samplerAnisotropy pattern in the "Base features" block of CapabilitiesVK::GetEnabledDeviceFeatures (the same block that already wires fillModeNonSolid and samplerAnisotropy):

required.textureCompressionETC2 = supported.textureCompressionETC2;
required.textureCompressionASTC_LDR = supported.textureCompressionASTC_LDR;
required.textureCompressionBC = supported.textureCompressionBC;

The read-back at ~line 670 then reports real hardware support with no further changes — this is the one piece #187077 wired on GLES/Metal but missed on Vulkan. (Note: ASTC HDR is already enabled this way at ~line 502 via VK_EXT_texture_compression_astc_hdr, so the three core LDR/BC/ETC2 features are the only gap.) It is a three-line change with no new extensions and no API surface impact.

Evidence device

  • Samsung Galaxy A54 5G (SM-A546E), Exynos 1380, Mali-G68 MP5
  • Android 16 (SDK 36), android.hardware.vulkan.version=4206592 (Vulkan 1.3)
  • Impeller backend: Vulkan (confirmed via logcat)
  • Hardware supports ETC2 (mandatory on Mali) and ASTC LDR

Impact

  • flutter_gpu consumers cannot use compressed textures on Android/Vulkan at all.
  • flutter_scene 0.18.x ships a KTX2/Basis pipeline that silently falls back to RGBA8 (≈8× texture memory, higher bandwidth) on the entire Android Vulkan population, while iOS (Metal) and Android GLES devices get compression.

Flutter doctor

flutter doctor -v (master channel)
[!] Flutter (Channel master, 3.46.0-1.0.pre-322, on Ubuntu 24.04.3 LTS 6.18.33.2-microsoft-standard-WSL2, locale C.UTF-8)
    • Flutter version 3.46.0-1.0.pre-322 on channel master at /home/guszxtavo/flutter-master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 47215701bc (10 days ago), 2026-06-27 02:19:27 -0400
    • Engine revision 47215701bc
    • Dart version 3.13.0 (build 3.13.0-254.0.dev)
    • DevTools version 2.59.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-dart-data-assets, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration, enable-riscv64

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
    • Android SDK at /home/guszxtavo/Android/Sdk
    • Platform android-36, build-tools 36.0.0
    • Java version OpenJDK Runtime Environment (build 17.0.19+10-1-24.04.2-Ubuntu)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Network resources
    • All expected network resources are available.

Test device (connected over adb Wi-Fi during repro): SM-A546E (Galaxy A54 5G), android-arm64, Android 16 (API 36), Exynos 1380 / Mali-G68 MP5, android.hardware.vulkan.version=4206592 (Vulkan 1.3).

Activity

  1. added
    engineflutter/engine related. See also e: labels.
    e: impellerImpeller rendering backend issues and features requests
    platform-androidAndroid applications specifically
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    c: regressionIt was better in the past than it is now
    on Jul 8, 2026
  2. added a commit that references this issue on Aug 4, 2026
    352f8ee
  3. github-actions commented on Aug 18, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  4. locked as resolved and limited conversation to collaborators on Aug 18, 2026
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

    c: regressionIt was better in the past than it is nowe: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyteam-fluttergpuOwned by Flutter GPU team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions