Skip to main content

ctt_intel_texture_compressor/
bc6h.rs

1//! BC6H block compression — RGB HDR (half-precision float).
2//!
3//! # Input format
4//!
5//! Expects an [`RgbaF16Surface`] with **`R16 G16 B16 A16` interleaved** pixel
6//! data (8 bytes per pixel). Each channel is a **little-endian IEEE 754
7//! binary16 (half-precision) float**. The alpha channel is present in the
8//! layout but **ignored** by the encoder (it is set to zero internally).
9//!
10//! # Output
11//!
12//! Each 4×4 texel block is encoded into **16 bytes** (1 byte/pixel). The
13//! format stores unsigned half-float endpoints; signed BC6H is not supported
14//! by this encoder.
15
16use crate::RgbaF16Surface;
17use crate::bindings::kernel;
18
19#[derive(Debug, Copy, Clone)]
20pub struct EncodeSettings {
21    pub slow_mode: bool,
22    pub fast_mode: bool,
23    pub refine_iterations_1p: u32,
24    pub refine_iterations_2p: u32,
25    pub fast_skip_threshold: u32,
26}
27
28#[must_use]
29pub fn calc_output_size(width: u32, height: u32) -> usize {
30    // BC6H uses a fixed block size of 16 bytes (128 bits) and a fixed tile size of 4x4 texels.
31    let block_count = (width.div_ceil(4) * height.div_ceil(4)) as usize;
32    block_count * 16
33}
34
35#[must_use]
36pub fn compress_blocks(settings: &EncodeSettings, surface: &RgbaF16Surface) -> Vec<u8> {
37    let output_size = calc_output_size(surface.width, surface.height);
38    let mut output = vec![0u8; output_size];
39    compress_blocks_into(settings, surface, &mut output);
40    output
41}
42
43/// Compresses an [`RgbaF16Surface`] into BC6H blocks.
44///
45/// The surface must contain `R16 G16 B16 A16` interleaved pixel data (8 bytes
46/// per pixel) where each channel is a little-endian f16. Only the R, G, and B
47/// channels are encoded; the alpha channel is ignored.
48///
49/// # Panics
50///
51/// Panics if `blocks.len()` does not equal [`calc_output_size`] for the given
52/// surface dimensions.
53pub fn compress_blocks_into(
54    settings: &EncodeSettings,
55    surface: &RgbaF16Surface,
56    blocks: &mut [u8],
57) {
58    assert_eq!(
59        blocks.len(),
60        calc_output_size(surface.width, surface.height)
61    );
62    // SAFETY: The ISPC function does not mutate the source surface; the `*mut u8`
63    // pointer type is an artifact of the C header declaration.
64    let mut surface = kernel::rgba_surface {
65        width: surface.width as i32,
66        height: surface.height as i32,
67        stride: surface.stride as i32,
68        ptr: surface.data.as_ptr() as *mut u8,
69    };
70    let mut settings = kernel::bc6h_enc_settings {
71        slow_mode: settings.slow_mode,
72        fast_mode: settings.fast_mode,
73        refineIterations_1p: settings.refine_iterations_1p as i32,
74        refineIterations_2p: settings.refine_iterations_2p as i32,
75        fastSkipThreshold: settings.fast_skip_threshold as i32,
76    };
77
78    unsafe {
79        kernel::CompressBlocksBC6H_ispc(&mut surface, blocks.as_mut_ptr(), &mut settings);
80    }
81}
82
83pub fn very_fast_settings() -> EncodeSettings {
84    EncodeSettings {
85        slow_mode: false,
86        fast_mode: true,
87        fast_skip_threshold: 0,
88        refine_iterations_1p: 0,
89        refine_iterations_2p: 0,
90    }
91}
92
93pub fn fast_settings() -> EncodeSettings {
94    EncodeSettings {
95        slow_mode: false,
96        fast_mode: true,
97        fast_skip_threshold: 2,
98        refine_iterations_1p: 0,
99        refine_iterations_2p: 1,
100    }
101}
102
103pub fn basic_settings() -> EncodeSettings {
104    EncodeSettings {
105        slow_mode: false,
106        fast_mode: false,
107        fast_skip_threshold: 4,
108        refine_iterations_1p: 2,
109        refine_iterations_2p: 2,
110    }
111}
112
113pub fn slow_settings() -> EncodeSettings {
114    EncodeSettings {
115        slow_mode: true,
116        fast_mode: false,
117        fast_skip_threshold: 10,
118        refine_iterations_1p: 2,
119        refine_iterations_2p: 2,
120    }
121}
122
123pub fn very_slow_settings() -> EncodeSettings {
124    EncodeSettings {
125        slow_mode: true,
126        fast_mode: false,
127        fast_skip_threshold: 32,
128        refine_iterations_1p: 2,
129        refine_iterations_2p: 2,
130    }
131}