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>;