pub(crate) use crate::quality::Quality;
pub(crate) mod backend;
#[cfg(any(
feature = "encoder-intel",
feature = "encoder-bc7enc",
feature = "encoder-etcpak",
feature = "encoder-amd",
))]
pub(crate) mod parallel;
#[cfg(any(feature = "encoder-intel", feature = "encoder-etcpak"))]
mod edge;
#[cfg(feature = "encoder-intel")]
pub mod ispc;
#[cfg(feature = "encoder-bc7enc")]
pub mod bc7enc;
#[cfg(feature = "encoder-etcpak")]
pub mod etcpak;
#[cfg(feature = "encoder-astcenc")]
pub mod astcenc;
#[cfg(feature = "encoder-amd")]
pub mod compressonator;
#[cfg(all(
test,
feature = "rayon",
any(
feature = "encoder-intel",
feature = "encoder-bc7enc",
feature = "encoder-etcpak",
feature = "encoder-amd",
feature = "encoder-astcenc",
)
))]
pub(crate) fn assert_parallel_matches_serial(encode: impl Fn() -> Vec<u8> + Sync) {
let pool = |threads| {
rayon::ThreadPoolBuilder::new()
.num_threads(threads)
.build()
.unwrap()
};
let serial = pool(1).install(&encode);
let parallel = pool(2).install(&encode);
assert_eq!(parallel, serial);
}
#[derive(Debug, Clone, Default)]
pub enum Encoder {
#[default]
Auto,
#[cfg(feature = "encoder-bc7enc")]
Bc7enc(bc7enc::Bc7encSettings),
#[cfg(feature = "encoder-intel")]
Intel(ispc::IspcSettings),
#[cfg(feature = "encoder-etcpak")]
Etcpak(etcpak::EtcpakSettings),
#[cfg(feature = "encoder-amd")]
Amd(compressonator::AmdSettings),
#[cfg(feature = "encoder-astcenc")]
Astcenc(astcenc::AstcencSettings),
}
pub struct EncoderInfo {
pub name: &'static str,
pub supported_formats: &'static [ktx2::Format],
}
pub fn resolve_auto_encoder(format: ktx2::Format) -> Option<Encoder> {
#[cfg_attr(
not(any(
feature = "encoder-bc7enc",
feature = "encoder-intel",
feature = "encoder-etcpak",
feature = "encoder-amd",
feature = "encoder-astcenc",
)),
expect(unused_imports)
)]
use backend::Encoder as _;
#[cfg(feature = "encoder-bc7enc")]
if bc7enc::Bc7encEncoder::supported_formats().contains(&format) {
return Some(Encoder::Bc7enc(Default::default()));
}
#[cfg(feature = "encoder-intel")]
if ispc::IspcEncoder::supported_formats().contains(&format) {
return Some(Encoder::Intel(Default::default()));
}
#[cfg(feature = "encoder-etcpak")]
if etcpak::EtcpakEncoder::supported_formats().contains(&format) {
return Some(Encoder::Etcpak(Default::default()));
}
#[cfg(feature = "encoder-amd")]
if compressonator::CompressonatorEncoder::supported_formats().contains(&format) {
return Some(Encoder::Amd(Default::default()));
}
#[cfg(feature = "encoder-astcenc")]
if astcenc::AstcencEncoder::supported_formats().contains(&format) {
return Some(Encoder::Astcenc(Default::default()));
}
let _ = format;
None
}
pub fn compiled_in_encoders() -> Vec<EncoderInfo> {
#[cfg_attr(
not(any(
feature = "encoder-bc7enc",
feature = "encoder-intel",
feature = "encoder-etcpak",
feature = "encoder-amd",
feature = "encoder-astcenc",
)),
expect(unused_imports)
)]
use backend::Encoder as _;
vec![
#[cfg(feature = "encoder-bc7enc")]
EncoderInfo {
name: bc7enc::Bc7encEncoder::name(),
supported_formats: bc7enc::Bc7encEncoder::supported_formats(),
},
#[cfg(feature = "encoder-intel")]
EncoderInfo {
name: ispc::IspcEncoder::name(),
supported_formats: ispc::IspcEncoder::supported_formats(),
},
#[cfg(feature = "encoder-etcpak")]
EncoderInfo {
name: etcpak::EtcpakEncoder::name(),
supported_formats: etcpak::EtcpakEncoder::supported_formats(),
},
#[cfg(feature = "encoder-amd")]
EncoderInfo {
name: compressonator::CompressonatorEncoder::name(),
supported_formats: compressonator::CompressonatorEncoder::supported_formats(),
},
#[cfg(feature = "encoder-astcenc")]
EncoderInfo {
name: astcenc::AstcencEncoder::name(),
supported_formats: astcenc::AstcencEncoder::supported_formats(),
},
]
}
#[cfg(test)]
mod tests {
use super::*;
fn encoder_name(encoder: &Encoder) -> &'static str {
match encoder {
Encoder::Auto => "auto",
#[cfg(feature = "encoder-bc7enc")]
Encoder::Bc7enc(_) => "bc7e",
#[cfg(feature = "encoder-intel")]
Encoder::Intel(_) => "intel",
#[cfg(feature = "encoder-etcpak")]
Encoder::Etcpak(_) => "etcpak",
#[cfg(feature = "encoder-amd")]
Encoder::Amd(_) => "amd",
#[cfg(feature = "encoder-astcenc")]
Encoder::Astcenc(_) => "astcenc",
}
}
#[test]
fn auto_resolution_matches_compiled_encoder_priority() {
let encoders = compiled_in_encoders();
for info in &encoders {
for &format in info.supported_formats {
let expected = encoders
.iter()
.find(|candidate| candidate.supported_formats.contains(&format))
.unwrap()
.name;
let resolved = resolve_auto_encoder(format).unwrap();
assert_eq!(encoder_name(&resolved), expected, "format {format:?}");
}
}
}
}