Fixed crash when transcoding one- or two-channel KTX2 textures (#12629)
# Objective Fixes a crash when transcoding one- or two-channel KTX2 textures ## Solution transcoded array has been pre-allocated up to levels.len using a macros. Rgb8 transcoding already uses that and addresses transcoded array by an index. R8UnormSrgb and Rg8UnormSrgb were pushing on top of the transcoded vec, resulting in first levels.len() vectors to stay empty, and second levels.len() levels actually being transcoded, which then resulted in out of bounds read when copying levels to gpu
This commit is contained in:
parent
a362c278bb
commit
7a9a459a40
@ -90,14 +90,12 @@ pub fn ktx2_buffer_to_image(
|
||||
TranscodeFormat::R8UnormSrgb => {
|
||||
let (mut original_width, mut original_height) = (width, height);
|
||||
|
||||
for level_data in &levels {
|
||||
transcoded.push(
|
||||
level_data
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|v| (Srgba::gamma_function(v as f32 / 255.) * 255.).floor() as u8)
|
||||
.collect::<Vec<u8>>(),
|
||||
);
|
||||
for (level, level_data) in levels.iter().enumerate() {
|
||||
transcoded[level] = level_data
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|v| (Srgba::gamma_function(v as f32 / 255.) * 255.).floor() as u8)
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
// Next mip dimensions are half the current, minimum 1x1
|
||||
original_width = (original_width / 2).max(1);
|
||||
@ -109,14 +107,12 @@ pub fn ktx2_buffer_to_image(
|
||||
TranscodeFormat::Rg8UnormSrgb => {
|
||||
let (mut original_width, mut original_height) = (width, height);
|
||||
|
||||
for level_data in &levels {
|
||||
transcoded.push(
|
||||
level_data
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|v| (Srgba::gamma_function(v as f32 / 255.) * 255.).floor() as u8)
|
||||
.collect::<Vec<u8>>(),
|
||||
);
|
||||
for (level, level_data) in levels.iter().enumerate() {
|
||||
transcoded[level] = level_data
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|v| (Srgba::gamma_function(v as f32 / 255.) * 255.).floor() as u8)
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
// Next mip dimensions are half the current, minimum 1x1
|
||||
original_width = (original_width / 2).max(1);
|
||||
@ -1493,3 +1489,36 @@ pub fn ktx2_format_to_texture_format(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::texture::CompressedImageFormats;
|
||||
|
||||
use super::ktx2_buffer_to_image;
|
||||
|
||||
#[test]
|
||||
fn test_ktx_levels() {
|
||||
// R8UnormSrgb textture with 4x4 pixels data and 3 levels of mipmaps
|
||||
let buffer = vec![
|
||||
0xab, 0x4b, 0x54, 0x58, 0x20, 0x32, 0x30, 0xbb, 0x0d, 10, 0x1a, 10, 0x0f, 0, 0, 0, 1,
|
||||
0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x98, 0, 0, 0, 0x2c, 0, 0, 0, 0xc4, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0x28, 1, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x10,
|
||||
0, 0, 0, 0, 0, 0, 0, 0x24, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
|
||||
0, 0, 0, 0x20, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x2c, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0x28, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0x12, 0, 0, 0, 0x4b, 0x54, 0x58,
|
||||
0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0, 0x72, 0x64, 0, 0,
|
||||
0, 0x10, 0, 0, 0, 0x4b, 0x54, 0x58, 0x73, 0x77, 0x69, 0x7a, 0x7a, 0x6c, 0x65, 0, 0x72,
|
||||
0x72, 0x72, 0x31, 0, 0x2c, 0, 0, 0, 0x4b, 0x54, 0x58, 0x77, 0x72, 0x69, 0x74, 0x65,
|
||||
0x72, 0, 0x74, 0x6f, 0x6b, 0x74, 0x78, 0x20, 0x76, 0x34, 0x2e, 0x33, 0x2e, 0x30, 0x7e,
|
||||
0x32, 0x38, 0x20, 0x2f, 0x20, 0x6c, 0x69, 0x62, 0x6b, 0x74, 0x78, 0x20, 0x76, 0x34,
|
||||
0x2e, 0x33, 0x2e, 0x30, 0x7e, 0x31, 0, 0x4a, 0, 0, 0, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
|
||||
0x4a,
|
||||
];
|
||||
let supported_compressed_formats = CompressedImageFormats::empty();
|
||||
let result = ktx2_buffer_to_image(&buffer, supported_compressed_formats, true);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user