Skip to content

Commit 3080040

Browse files
authored
add native zstd support (#19793)
# Objective - add support for alternate zstd backend through `zstd` for faster decompression ## Solution - make existing `zstd` feature only specify that support is required, disambiguate which backend to use via two other features `zstd_native` and `zstd_rust`. - Similar to the approach taken by #18411, but we keep current behavior by defaulting to the rust implementation because its safer, and isolate this change. NOTE: the default feature-set may seem to not currently require `zstd`, but it does, it is enabled transitively by the `tonemapping_luts` feature, which is a default feature. Thus this does not add default features. ## Testing - Cargo clippy on both feature combinations
1 parent b62b14c commit 3080040

File tree

7 files changed

+43
-8
lines changed

7 files changed

+43
-8
lines changed

Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ default = [
165165
"webgl2",
166166
"x11",
167167
"debug",
168+
"zstd_rust",
168169
]
169170

170171
# Recommended defaults for no_std applications
@@ -381,8 +382,11 @@ webp = ["bevy_internal/webp"]
381382
# For KTX2 supercompression
382383
zlib = ["bevy_internal/zlib"]
383384

384-
# For KTX2 supercompression
385-
zstd = ["bevy_internal/zstd"]
385+
# For KTX2 Zstandard decompression using pure rust [ruzstd](https://crates.io/crates/ruzstd). This is the safe default. For maximum performance, use "zstd_c".
386+
zstd_rust = ["bevy_internal/zstd_rust"]
387+
388+
# For KTX2 Zstandard decompression using [zstd](https://crates.io/crates/zstd). This is a faster backend, but uses unsafe C bindings. For the safe option, stick to the default backend with "zstd_rust".
389+
zstd_c = ["bevy_internal/zstd_c"]
386390

387391
# FLAC audio format support
388392
flac = ["bevy_internal/flac"]
@@ -451,7 +455,7 @@ android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
451455
detailed_trace = ["bevy_internal/detailed_trace"]
452456

453457
# 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`.
454-
tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "zstd"]
458+
tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "bevy_image/zstd"]
455459

456460
# Include SMAA Look Up Tables KTX2 Files
457461
smaa_luts = ["bevy_internal/smaa_luts"]

crates/bevy_image/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,14 @@ serialize = ["bevy_reflect", "bevy_platform/serialize"]
3636

3737
# For ktx2 supercompression
3838
zlib = ["flate2"]
39-
zstd = ["ruzstd"]
39+
40+
# A marker feature indicating zstd support is required for a particular feature.
41+
# A backend must be chosen by enabling either the "zstd_rust" or the "zstd_c" feature.
42+
zstd = []
43+
# Pure-rust zstd implementation (safer)
44+
zstd_rust = ["zstd", "dep:ruzstd"]
45+
# Binding to zstd C implementation (faster)
46+
zstd_c = ["zstd", "dep:zstd"]
4047

4148
# Enables compressed KTX2 UASTC texture output on the asset processor
4249
compressed_image_saver = ["basis-universal"]
@@ -73,6 +80,7 @@ ddsfile = { version = "0.5.2", optional = true }
7380
ktx2 = { version = "0.4.0", optional = true }
7481
# For ktx2 supercompression
7582
flate2 = { version = "1.0.22", optional = true }
83+
zstd = { version = "0.13.3", optional = true }
7684
ruzstd = { version = "0.8.0", optional = true }
7785
# For transcoding of UASTC/ETC1S universal formats, and for .basis file support
7886
basis-universal = { version = "0.3.0", optional = true }

crates/bevy_image/src/ktx2.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[cfg(any(feature = "flate2", feature = "ruzstd"))]
1+
#[cfg(any(feature = "flate2", feature = "zstd_rust"))]
22
use std::io::Read;
33

44
#[cfg(feature = "basis-universal")]
@@ -7,7 +7,7 @@ use basis_universal::{
77
};
88
use bevy_color::Srgba;
99
use bevy_utils::default;
10-
#[cfg(any(feature = "flate2", feature = "ruzstd"))]
10+
#[cfg(any(feature = "flate2", feature = "zstd_rust", feature = "zstd_c"))]
1111
use ktx2::SupercompressionScheme;
1212
use ktx2::{
1313
ChannelTypeQualifiers, ColorModel, DfdBlockBasic, DfdBlockHeaderBasic, DfdHeader, Header,
@@ -58,7 +58,7 @@ pub fn ktx2_buffer_to_image(
5858
})?;
5959
levels.push(decompressed);
6060
}
61-
#[cfg(feature = "ruzstd")]
61+
#[cfg(feature = "zstd_rust")]
6262
SupercompressionScheme::Zstandard => {
6363
let mut cursor = std::io::Cursor::new(level.data);
6464
let mut decoder = ruzstd::decoding::StreamingDecoder::new(&mut cursor)
@@ -71,6 +71,14 @@ pub fn ktx2_buffer_to_image(
7171
})?;
7272
levels.push(decompressed);
7373
}
74+
#[cfg(all(feature = "zstd_c", not(feature = "zstd_rust")))]
75+
SupercompressionScheme::Zstandard => {
76+
levels.push(zstd::decode_all(level.data).map_err(|err| {
77+
TextureError::SuperDecompressionError(format!(
78+
"Failed to decompress {supercompression_scheme:?} for mip {level_index}: {err:?}",
79+
))
80+
})?);
81+
}
7482
_ => {
7583
return Err(TextureError::SuperDecompressionError(format!(
7684
"Unsupported supercompression scheme: {supercompression_scheme:?}",

crates/bevy_image/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ pub mod prelude {
1010
};
1111
}
1212

13+
#[cfg(all(feature = "zstd", not(feature = "zstd_rust"), not(feature = "zstd_c")))]
14+
compile_error!(
15+
"Choosing a zstd backend is required for zstd support. Please enable either the \"zstd_rust\" or the \"zstd_c\" feature."
16+
);
17+
1318
mod image;
1419
pub use self::image::*;
1520
#[cfg(feature = "basis-universal")]

crates/bevy_internal/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ ktx2 = ["bevy_image/ktx2", "bevy_render/ktx2"]
4343
# For ktx2 supercompression
4444
zlib = ["bevy_image/zlib"]
4545
zstd = ["bevy_image/zstd"]
46+
zstd_rust = ["bevy_image/zstd_rust"]
47+
zstd_c = ["bevy_image/zstd_c"]
4648

4749
# Image format support (PNG enabled by default)
4850
bmp = ["bevy_image/bmp"]

docs/cargo_features.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The default feature set enables most of the expected features of a game engine,
5454
|vorbis|OGG/VORBIS audio format support|
5555
|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.|
5656
|x11|X11 display server support|
57-
|zstd|For KTX2 supercompression|
57+
|zstd_rust|For KTX2 Zstandard decompression using pure rust [ruzstd](https://crates.io/crates/ruzstd). This is the safe default. For maximum performance, use "zstd_c".|
5858

5959
### Optional Features
6060

@@ -130,3 +130,4 @@ The default feature set enables most of the expected features of a game engine,
130130
|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.|
131131
|webp|WebP image format support|
132132
|zlib|For KTX2 supercompression|
133+
|zstd_c|For KTX2 Zstandard decompression using [zstd](https://crates.io/crates/zstd). This is a faster backend, but uses unsafe C bindings. For the safe option, stick to the default backend with "zstd_rust".|
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: New zstd backend
3+
pull_requests: [19793]
4+
---
5+
6+
A more performant zstd backend has been added for texture decompression. To enable it, disable default-features and enable feature "zstd_c".
7+
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)

0 commit comments

Comments
 (0)