Skip to main content

ctt_intel_texture_compressor/
lib.rs

1#[cfg(feature = "prebuilt")]
2extern crate ctt_intel_texture_compressor_prebuilt;
3
4pub mod bindings;
5
6pub mod bc1;
7pub mod bc3;
8pub mod bc4;
9pub mod bc5;
10pub mod bc6h;
11pub mod bc7;
12pub mod etc1;
13
14/// Describes a 2D image to block-compress.
15///
16/// `COMPONENTS` is the number of **bytes per pixel** in the source data. This
17/// determines the expected tightly-packed stride (`width * COMPONENTS`) and is
18/// used to validate that `data` is large enough. The actual channel layout
19/// depends on which encoder consumes the surface — see the individual format
20/// modules for details.
21///
22/// # Available surface type aliases
23///
24/// | Alias | `COMPONENTS` | Layout | Used by |
25/// |---|---|---|---|
26/// | [`RSurface`] | 1 | `R8` (1 byte/pixel) | [`bc4`] |
27/// | [`RgSurface`] | 2 | `R8 G8` interleaved (2 bytes/pixel) | [`bc5`] |
28/// | [`RgbaSurface`] | 4 | `R8 G8 B8 A8` interleaved (4 bytes/pixel) | [`bc1`], [`bc3`], [`bc7`], [`etc1`] |
29/// | [`RgbaF16Surface`] | 8 | `R16 G16 B16 A16` interleaved (8 bytes/pixel) | [`bc6h`] |
30#[derive(Debug, Copy, Clone)]
31pub struct Surface<'a, const COMPONENTS: usize> {
32    /// The raw pixel data for the image.
33    ///
34    /// The byte interpretation depends on the encoder that consumes this
35    /// surface. For most formats, each byte is one u8 channel sample. For
36    /// [`bc6h`], every two bytes form a little-endian f16 channel sample.
37    ///
38    /// The data does not need to be tightly packed, but if it isn't, `stride`
39    /// must differ from `width * COMPONENTS`.
40    ///
41    /// Expected to be at least `stride * height` bytes.
42    pub data: &'a [u8],
43    /// The width of the image in texels.
44    pub width: u32,
45    /// The height of the image in texels.
46    pub height: u32,
47    /// The stride between rows of the image, in bytes.
48    ///
49    /// For tightly-packed data this is `width * COMPONENTS`.
50    pub stride: u32,
51}
52
53impl<'a, const COMPONENTS: usize> Surface<'a, COMPONENTS> {
54    /// Creates a new surface, validating the preconditions required by the
55    /// underlying ISPC kernels.
56    ///
57    /// # Panics
58    ///
59    /// Panics if:
60    /// - `width` or `height` is zero,
61    /// - `width` or `height` is not a multiple of 4 (the ISPC kernels process
62    ///   whole 4×4 blocks and will silently drop partial edge blocks
63    ///   otherwise),
64    /// - `width`, `height`, or `stride` exceed `i32::MAX`,
65    /// - `stride` is less than `width * COMPONENTS`,
66    /// - `data.len()` is less than `stride * height`.
67    pub fn new(data: &'a [u8], width: u32, height: u32, stride: u32) -> Self {
68        assert!(width > 0 && height > 0, "width and height must be non-zero");
69        assert!(
70            width.is_multiple_of(4),
71            "width {width} must be a multiple of 4 (ISPC kernels only process whole 4×4 blocks)",
72        );
73        assert!(
74            height.is_multiple_of(4),
75            "height {height} must be a multiple of 4 (ISPC kernels only process whole 4×4 blocks)",
76        );
77        assert!(
78            i32::try_from(width).is_ok(),
79            "width {width} exceeds i32::MAX"
80        );
81        assert!(
82            i32::try_from(height).is_ok(),
83            "height {height} exceeds i32::MAX"
84        );
85        assert!(
86            i32::try_from(stride).is_ok(),
87            "stride {stride} exceeds i32::MAX"
88        );
89        let width_components = (width as usize)
90            .checked_mul(COMPONENTS)
91            .expect("width * COMPONENTS overflows usize");
92        assert!(
93            stride as usize >= width_components,
94            "stride {stride} is less than width * COMPONENTS ({} * {COMPONENTS} = {width_components})",
95            width,
96        );
97        let required = (stride as usize)
98            .checked_mul(height as usize)
99            .expect("stride * height overflows usize");
100        assert!(
101            data.len() >= required,
102            "data length {} is less than stride * height ({required})",
103            data.len()
104        );
105        Self {
106            data,
107            width,
108            height,
109            stride,
110        }
111    }
112}
113
114/// 4-channel, 8-bit surface: `R8 G8 B8 A8` — 4 bytes per pixel.
115///
116/// Used by [`bc1`], [`bc3`], [`bc7`], and [`etc1`].
117pub type RgbaSurface<'a> = Surface<'a, 4>;
118
119/// 2-channel, 8-bit surface: `R8 G8` interleaved — 2 bytes per pixel.
120///
121/// Used by [`bc5`].
122pub type RgSurface<'a> = Surface<'a, 2>;
123
124/// 1-channel, 8-bit surface: `R8` — 1 byte per pixel.
125///
126/// Used by [`bc4`].
127pub type RSurface<'a> = Surface<'a, 1>;
128
129/// 4-channel, 16-bit surface: `R16 G16 B16 A16` — 8 bytes per pixel.
130///
131/// Each channel is a little-endian IEEE 754 binary16 (half-precision) float.
132/// The alpha channel is present in the layout but ignored by [`bc6h`].
133pub type RgbaF16Surface<'a> = Surface<'a, 8>;