UASTC KTX2 with a single (R) channel fails to load: "Failed to transcode mip level 0 from UASTC to BC4: TranscodeFailed"

Aperta
#26,295 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
rust
Ambito
backend

Direzione di ricerca

Start in crates/bevy_image/src/ktx2.rs at the TranscodeFormat::Uastc branch and trace how source mip and layer slices are sized for each target format. The report shows BC4 fails because its 8-byte blocks are used to size 16-byte UASTC source blocks; compare the BC target fix with the separate uncompressed fallback, which has its own reported failure. Done means single-channel UASTC KTX2 loads on the affected compressed targets without regressing RGBA UASTC.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

A-Assets A-Rendering C-Bug D-Straightforward S-Ready-For-Implementation X-Uncontroversial

Bevy version

0.20.0 (bevy_image 0.20.0). The code in question is unchanged on main as of 2026-10-24; 0.19.1 has it too.

What you did

Loaded a single-channel UASTC KTX2 (a height map) on a GPU with BC support:

ktx create --format R8_UNORM --encode uastc --generate-mipmap --assign-tf linear h.png h.ktx2   # KTX-Software 4.4.2
Image::from_buffer(&bytes, ImageType::Extension("ktx2"), CompressedImageFormats::BC,
                   false, ImageSampler::Default, RenderAssetUsages::default())

What went wrong

failed to decompress an image: Failed to transcode mip level 0 from UASTC to BC4: TranscodeFailed

An RGBA UASTC file built the same way loads fine as Bc7RgbaUnorm.

Cause

In crates/bevy_image/src/ktx2.rs, the TranscodeFormat::Uastc branch works out how many bytes of source data each level and layer takes using the target format's block size:

let block_bytes = texture_format_info.block_copy_size(None).unwrap(); // target format: BC4 = 8
let level_bytes = (num_blocks_x * num_blocks_y * block_bytes) as usize;
transcoder.transcode_slice(&level_data[offset..(offset + level_bytes)], ...)

UASTC blocks are always 4×4 and 16 bytes. BC4 and EacR11Unorm blocks are 8 bytes, so the transcoder gets only half of each level. basisu_lowlevel_uastc_transcoder::transcode_slice checks image_data_size < total_expected_block_bytes and returns false. BC7, BC5 and ASTC 4×4 targets work only because their blocks happen to be 16 bytes too. This affects every UASTC texture with TextureChannelLayout::Rrr on BC- or ETC2-capable hardware.

Fix (tested for BC targets)

Size the source slice in UASTC blocks:

// The source is UASTC whatever the target: 4x4 blocks of 16 bytes.
let (block_width_pixels, block_height_pixels) = (4, 4);
let block_bytes = 16;

I patched a local copy of bevy_image 0.20.0 with this and loaded the following with CompressedImageFormats::BC:

file stock 0.20.0 patched
R8 UASTC 64×64, 7 mips TranscodeFailed (BC4) Bc4RUnorm, 7 mips
R8 UASTC 60×36, 6 mips TranscodeFailed (BC4) Bc4RUnorm, 6 mips
RGBA8 UASTC 64×64, 7 mips Bc7RgbaUnorm Bc7RgbaUnorm

Related: the uncompressed fallback

With CompressedImageFormats::NONE the same branch is also wrong, and the fix above does not repair it:

  • stock: R8 UASTC gives TranscodeFailed (RGBA32), and RGBA8 UASTC panics on the out-of-range slice;
  • patched: the process aborts with malloc(): corrupted top size inside transcode_slice (basis-universal 0.3.1).

So that path needs its own look: its output is RGBA32, while get_transcoded_formats labels it R8Unorm / Rg8Unorm. I haven't dug further. A fix for the compressed targets alone shouldn't change it, since it can't load either way today.

Lingua principale
Rust
Stelle
49.7k
Fork
5k
Merge medio
3g 19h
PR unite (30g)
134

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di bevyengine/bevy

Tutte le issue di bevyengine/bevy

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.