Skip to content

add native zstd support #19793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ default = [
"webgl2",
"x11",
"debug",
"zstd_rust",
]

# Recommended defaults for no_std applications
Expand Down Expand Up @@ -381,8 +382,11 @@ webp = ["bevy_internal/webp"]
# For KTX2 supercompression
zlib = ["bevy_internal/zlib"]

# For KTX2 supercompression
zstd = ["bevy_internal/zstd"]
# For KTX2 Zstandard decompression using pure rust [ruzstd](https://crates.io/crates/ruzstd)
zstd_rust = ["bevy_internal/zstd_rust"]

# For KTX2 Zstandard decompression using [zstd](https://crates.io/crates/zstd)
zstd_c = ["bevy_internal/zstd_c"]

# FLAC audio format support
flac = ["bevy_internal/flac"]
Expand Down Expand Up @@ -451,7 +455,7 @@ android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
detailed_trace = ["bevy_internal/detailed_trace"]

# Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method for your `Camera2d` or `Camera3d`.
tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "zstd"]
tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "bevy_image/zstd"]

# Include SMAA Look Up Tables KTX2 Files
smaa_luts = ["bevy_internal/smaa_luts"]
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_image/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ serialize = ["bevy_reflect", "bevy_platform/serialize"]

# For ktx2 supercompression
zlib = ["flate2"]
zstd = ["ruzstd"]

# A marker feature indicating zstd support is required for a particular feature.
# A backend must be chosen by enabling either the "zstd_rust" or the "zstd_c" feature.
zstd = []
# Pure-rust zstd implementation (safer)
zstd_rust = ["zstd", "dep:ruzstd"]
# Binding to zstd C implementation (faster)
zstd_c = ["zstd", "dep:zstd"]

# Enables compressed KTX2 UASTC texture output on the asset processor
compressed_image_saver = ["basis-universal"]
Expand Down Expand Up @@ -73,6 +80,7 @@ ddsfile = { version = "0.5.2", optional = true }
ktx2 = { version = "0.4.0", optional = true }
# For ktx2 supercompression
flate2 = { version = "1.0.22", optional = true }
zstd = { version = "0.13.3", optional = true }
ruzstd = { version = "0.8.0", optional = true }
# For transcoding of UASTC/ETC1S universal formats, and for .basis file support
basis-universal = { version = "0.3.0", optional = true }
Expand Down
14 changes: 11 additions & 3 deletions crates/bevy_image/src/ktx2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[cfg(any(feature = "flate2", feature = "ruzstd"))]
#[cfg(any(feature = "flate2", feature = "zstd_rust"))]
use std::io::Read;

#[cfg(feature = "basis-universal")]
Expand All @@ -7,7 +7,7 @@ use basis_universal::{
};
use bevy_color::Srgba;
use bevy_utils::default;
#[cfg(any(feature = "flate2", feature = "ruzstd"))]
#[cfg(any(feature = "flate2", feature = "zstd_rust", feature = "zstd_c"))]
use ktx2::SupercompressionScheme;
use ktx2::{
ChannelTypeQualifiers, ColorModel, DfdBlockBasic, DfdBlockHeaderBasic, DfdHeader, Header,
Expand Down Expand Up @@ -58,7 +58,7 @@ pub fn ktx2_buffer_to_image(
})?;
levels.push(decompressed);
}
#[cfg(feature = "ruzstd")]
#[cfg(feature = "zstd_rust")]
SupercompressionScheme::Zstandard => {
let mut cursor = std::io::Cursor::new(level.data);
let mut decoder = ruzstd::decoding::StreamingDecoder::new(&mut cursor)
Expand All @@ -71,6 +71,14 @@ pub fn ktx2_buffer_to_image(
})?;
levels.push(decompressed);
}
#[cfg(all(feature = "zstd_c", not(feature = "zstd_rust")))]
SupercompressionScheme::Zstandard => {
levels.push(zstd::decode_all(level.data).map_err(|err| {
TextureError::SuperDecompressionError(format!(
"Failed to decompress {supercompression_scheme:?} for mip {level_index}: {err:?}",
))
})?);
}
_ => {
return Err(TextureError::SuperDecompressionError(format!(
"Unsupported supercompression scheme: {supercompression_scheme:?}",
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_image/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ pub mod prelude {
};
}

#[cfg(all(feature = "zstd", not(feature = "zstd_rust"), not(feature = "zstd_c")))]
compile_error!(
"Choosing a zstd backend is required for zstd support. Please enable either the \"zstd_rust\" or the \"zstd_c\" feature."
);

mod image;
pub use self::image::*;
#[cfg(feature = "basis-universal")]
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ ktx2 = ["bevy_image/ktx2", "bevy_render/ktx2"]
# For ktx2 supercompression
zlib = ["bevy_image/zlib"]
zstd = ["bevy_image/zstd"]
zstd_rust = ["bevy_image/zstd_rust"]
zstd_c = ["bevy_image/zstd_c"]

# Image format support (PNG enabled by default)
bmp = ["bevy_image/bmp"]
Expand Down
3 changes: 2 additions & 1 deletion docs/cargo_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The default feature set enables most of the expected features of a game engine,
|vorbis|OGG/VORBIS audio format support|
|webgl2|Enable some limitations to be able to use WebGL2. Please refer to the [WebGL2 and WebGPU](https://github.com/bevyengine/bevy/tree/latest/examples#webgl2-and-webgpu) section of the examples README for more information on how to run Wasm builds with WebGPU.|
|x11|X11 display server support|
|zstd|For KTX2 supercompression|
|zstd_rust|For KTX2 Zstandard decompression using pure rust [ruzstd](https://crates.io/crates/ruzstd)|

### Optional Features

Expand Down Expand Up @@ -130,3 +130,4 @@ The default feature set enables most of the expected features of a game engine,
|webgpu|Enable support for WebGPU in Wasm. When enabled, this feature will override the `webgl2` feature and you won't be able to run Wasm builds with WebGL2, only with WebGPU.|
|webp|WebP image format support|
|zlib|For KTX2 supercompression|
|zstd_c|For KTX2 Zstandard decompression using [zstd](https://crates.io/crates/zstd)|
7 changes: 7 additions & 0 deletions release-content/migration-guides/zstd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: New zstd backend
pull_requests: [19793]
---

A more performant zstd backend has been added for texture decompression. To enable it, disable default-features and enable feature "zstd_c".
If you have default-features disabled and use functionality that requires zstd decompression ("tonemapping_luts" or "ktx2"), you must choose a zstd implementation with one of the following feature flags: "zstd_c" (faster) or "zstd_rust" (safer)