bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.19k stars 3.57k forks source link

Some images compressed with `CompressedImageSaver` cause panics after loading #14315

Open Seldom-SE opened 4 months ago

Seldom-SE commented 4 months ago

Bevy version

0.14

Relevant system information

`AdapterInfo { name: "AMD Radeon RX 570 Series (RADV POLARIS10)", vendor: 4098, device: 26591, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 24.1.3-arch1.1", backend: Vulkan }`

What you did

Loaded a 50x50 white square made in GIMP preprocessed with bevy_asset::processor::process::LoadAndSave<bevy_render::texture::image_loader::ImageLoader, bevy_render::texture::compressed_image_saver::CompressedImageSaver>

What went wrong

thread 'Compute Task Pool (3)' panicked at /home/seldom/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.20.1/src/util/device.rs:174:26:
range end index 3744 out of range for slice of length 3616
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_render::render_asset::prepare_assets<bevy_render::texture::image::GpuImage>`!

Additional information

Panic also occurred with a 49x50 white rectangle made in GIMP, a 64x33 textured image downloaded from itch.io, and some 50x50 icons downloaded from icons8.com. Panic didn't occur with a large variety of images including larger and smaller ones, and from a variety of sources. Panics seem to be more common with smaller images, but not strictly so.

Repro: https://github.com/Seldom-SE/testetst/blob/b70266e9f3779c4c4858a5a449cfe6b2b2d06278/src/main.rs

bugsweeper commented 3 months ago
Error tells us that buffer with image mip-maps data is to low when using. Mip-maps divide image pixels to blocks, in current case that blocks has 4x4 pixels, and takes 16 pixels/bytes per block from data slice. I tried to follow creating and using that slice to figure out when something is going wrong. Results of investigation: Creating mipmaps is going here using basis-universal crate: Mip level Size of Mip Blocks New size Data size Data end
0 50x50 13x13=169 52x52 169*16=2704 2704
1 25x25 7x7=49 28x28 49*16=784 2704+784=3488
2 12x12 3x3=9 12x12 9*16=144 3488+144=3632
3 6x6 2x2=4 6x6 4*16=64 3632+64=3696
4 3x3 1x1=1 3x3 1*16=16 3696+16=3712
5 1x1 1x1=1 1x1 1*16=16 3712+16=3728
The problem is that new Image keeps "New size" for keeping full blocks instead of original Size Using mipmaps is going here in wgpu crate: Mip level Size of Mip Blocks Data size Data end
0 52x52 13x13=169 169*16=2704 2704
1 26x26 7x7=49 49*16=784 2704+784=3488
2 13x13 4x4=16 16*16=256 3488+256=3744

As you see starting from here mipmap level 2 use wrong data place. And gave me error: range end index 3744 out of range for slice of length 3728 I tried to set original size in Image - wgpu didn't like it. I tried to fill missed TranscodeParameters data fields (output_row_pitch_in_blocks_or_pixels and output_rows_in_pixels) - basis-universal's transcoder ignored it, because it is compressed. @superdump any hints? @Seldom-SE As a temporary solution, sizes in multiples of 4 can be used.