physis/bcn/
bc7.rs

1// SPDX-FileCopyrightText: 2023 Rudolf Kolbe
2// SPDX-License-Identifier: MIT
3
4use super::bitreader::BitReader;
5use super::color::color;
6use super::consts::{S_BPTC_A2, S_BPTC_A3, S_BPTC_FACTORS, S_BPTC_P2, S_BPTC_P3};
7use core::mem::swap;
8
9struct Bc7ModeInfo {
10    num_subsets: usize,
11    partition_bits: usize,
12    rotation_bits: usize,
13    index_selection_bits: usize,
14    color_bits: usize,
15    alpha_bits: usize,
16    endpoint_pbits: usize,
17    shared_pbits: usize,
18    index_bits: [usize; 2],
19}
20
21static S_BP7_MODE_INFO: [Bc7ModeInfo; 8] = [
22    //  +---------------------------- num subsets
23    //  |  +------------------------- partition bits
24    //  |  |  +---------------------- rotation bits
25    //  |  |  |  +------------------- index selection bits
26    //  |  |  |  |  +---------------- color bits
27    //  |  |  |  |  |  +------------- alpha bits
28    //  |  |  |  |  |  |  +---------- endpoint P-bits
29    //  |  |  |  |  |  |  |  +------- shared P-bits
30    //  |  |  |  |  |  |  |  |    +-- 2x index bits
31    // { 3, 4, 0, 0, 4, 0, 1, 0, { 3, 0 } }, // 0
32    // { 2, 6, 0, 0, 6, 0, 0, 1, { 3, 0 } }, // 1
33    // { 3, 6, 0, 0, 5, 0, 0, 0, { 2, 0 } }, // 2
34    // { 2, 6, 0, 0, 7, 0, 1, 0, { 2, 0 } }, // 3
35    // { 1, 0, 2, 1, 5, 6, 0, 0, { 2, 3 } }, // 4
36    // { 1, 0, 2, 0, 7, 8, 0, 0, { 2, 2 } }, // 5
37    // { 1, 0, 0, 0, 7, 7, 1, 0, { 4, 0 } }, // 6
38    // { 2, 6, 0, 0, 5, 5, 1, 0, { 2, 0 } }, // 7
39    Bc7ModeInfo {
40        num_subsets: 3,
41        partition_bits: 4,
42        rotation_bits: 0,
43        index_selection_bits: 0,
44        color_bits: 4,
45        alpha_bits: 0,
46        endpoint_pbits: 1,
47        shared_pbits: 0,
48        index_bits: [3, 0],
49    },
50    Bc7ModeInfo {
51        num_subsets: 2,
52        partition_bits: 6,
53        rotation_bits: 0,
54        index_selection_bits: 0,
55        color_bits: 6,
56        alpha_bits: 0,
57        endpoint_pbits: 0,
58        shared_pbits: 1,
59        index_bits: [3, 0],
60    },
61    Bc7ModeInfo {
62        num_subsets: 3,
63        partition_bits: 6,
64        rotation_bits: 0,
65        index_selection_bits: 0,
66        color_bits: 5,
67        alpha_bits: 0,
68        endpoint_pbits: 0,
69        shared_pbits: 0,
70        index_bits: [2, 0],
71    },
72    Bc7ModeInfo {
73        num_subsets: 2,
74        partition_bits: 6,
75        rotation_bits: 0,
76        index_selection_bits: 0,
77        color_bits: 7,
78        alpha_bits: 0,
79        endpoint_pbits: 1,
80        shared_pbits: 0,
81        index_bits: [2, 0],
82    },
83    Bc7ModeInfo {
84        num_subsets: 1,
85        partition_bits: 0,
86        rotation_bits: 2,
87        index_selection_bits: 1,
88        color_bits: 5,
89        alpha_bits: 6,
90        endpoint_pbits: 0,
91        shared_pbits: 0,
92        index_bits: [2, 3],
93    },
94    Bc7ModeInfo {
95        num_subsets: 1,
96        partition_bits: 0,
97        rotation_bits: 2,
98        index_selection_bits: 0,
99        color_bits: 7,
100        alpha_bits: 8,
101        endpoint_pbits: 0,
102        shared_pbits: 0,
103        index_bits: [2, 2],
104    },
105    Bc7ModeInfo {
106        num_subsets: 1,
107        partition_bits: 0,
108        rotation_bits: 0,
109        index_selection_bits: 0,
110        color_bits: 7,
111        alpha_bits: 7,
112        endpoint_pbits: 1,
113        shared_pbits: 0,
114        index_bits: [4, 0],
115    },
116    Bc7ModeInfo {
117        num_subsets: 2,
118        partition_bits: 6,
119        rotation_bits: 0,
120        index_selection_bits: 0,
121        color_bits: 5,
122        alpha_bits: 5,
123        endpoint_pbits: 1,
124        shared_pbits: 0,
125        index_bits: [2, 0],
126    },
127];
128
129#[inline]
130fn expand_quantized(v: u8, bits: usize) -> u8 {
131    let s = ((v as u16) << (8 - bits as u16)) as u8;
132    s | s.overflowing_shr(bits as u32).0
133}
134
135pub fn decode_bc7_block(data: &[u8], outbuf: &mut [u32]) {
136    let mut bit = BitReader::new(data, 0);
137    let mode = {
138        let mut mode = 0;
139        while 0 == bit.read(1) && mode < 8 {
140            mode += 1;
141        }
142        mode
143    };
144
145    if mode == 8 {
146        outbuf[0..16].fill(0);
147        return;
148    }
149
150    let mi: &Bc7ModeInfo = &S_BP7_MODE_INFO[mode];
151    let mode_pbits: usize = if 0 != mi.endpoint_pbits {
152        mi.endpoint_pbits
153    } else {
154        mi.shared_pbits
155    };
156
157    let partition_set_idx: usize = bit.read(mi.partition_bits) as usize;
158    let rotation_mode: u8 = bit.read(mi.rotation_bits) as u8;
159    let index_selection_mode: usize = bit.read(mi.index_selection_bits) as usize;
160
161    let mut ep_r: [u8; 6] = [0; 6];
162    let mut ep_g: [u8; 6] = [0; 6];
163    let mut ep_b: [u8; 6] = [0; 6];
164    let mut ep_a: [u8; 6] = [0; 6];
165
166    (0..mi.num_subsets).for_each(|ii| {
167        ep_r[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
168        ep_r[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
169    });
170
171    (0..mi.num_subsets).for_each(|ii| {
172        ep_g[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
173        ep_g[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
174    });
175
176    (0..mi.num_subsets).for_each(|ii| {
177        ep_b[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
178        ep_b[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
179    });
180
181    if mi.alpha_bits > 0 {
182        (0..mi.num_subsets).for_each(|ii| {
183            ep_a[ii * 2] = (bit.read(mi.alpha_bits) << mode_pbits) as u8;
184            ep_a[ii * 2 + 1] = (bit.read(mi.alpha_bits) << mode_pbits) as u8;
185        });
186    } else {
187        ep_a = [0xff; 6];
188    }
189
190    if 0 != mode_pbits {
191        (0..mi.num_subsets).for_each(|ii| {
192            let pda: u8 = bit.read(mode_pbits) as u8;
193            let pdb: u8 = if 0 == mi.shared_pbits {
194                bit.read(mode_pbits) as u8
195            } else {
196                pda
197            };
198
199            ep_r[ii * 2] |= pda;
200            ep_r[ii * 2 + 1] |= pdb;
201            ep_g[ii * 2] |= pda;
202            ep_g[ii * 2 + 1] |= pdb;
203            ep_b[ii * 2] |= pda;
204            ep_b[ii * 2 + 1] |= pdb;
205            ep_a[ii * 2] |= pda;
206            ep_a[ii * 2 + 1] |= pdb;
207        });
208    }
209
210    let color_bits: usize = mi.color_bits + mode_pbits;
211
212    (0..mi.num_subsets).for_each(|ii| {
213        ep_r[ii * 2] = expand_quantized(ep_r[ii * 2], color_bits);
214        ep_r[ii * 2 + 1] = expand_quantized(ep_r[ii * 2 + 1], color_bits);
215        ep_g[ii * 2] = expand_quantized(ep_g[ii * 2], color_bits);
216        ep_g[ii * 2 + 1] = expand_quantized(ep_g[ii * 2 + 1], color_bits);
217        ep_b[ii * 2] = expand_quantized(ep_b[ii * 2], color_bits);
218        ep_b[ii * 2 + 1] = expand_quantized(ep_b[ii * 2 + 1], color_bits);
219    });
220
221    if mi.alpha_bits > 0 {
222        let alpha_bits = mi.alpha_bits + mode_pbits;
223
224        (0..mi.num_subsets).for_each(|ii| {
225            ep_a[ii * 2] = expand_quantized(ep_a[ii * 2], alpha_bits);
226            ep_a[ii * 2 + 1] = expand_quantized(ep_a[ii * 2 + 1], alpha_bits);
227        });
228    }
229
230    let has_index_bits1: bool = 0 != mi.index_bits[1];
231
232    let factors: [[u8; 16]; 2] = [
233        S_BPTC_FACTORS[mi.index_bits[0] - 2],
234        if has_index_bits1 {
235            S_BPTC_FACTORS[mi.index_bits[1] - 2]
236        } else {
237            S_BPTC_FACTORS[mi.index_bits[0] - 2]
238        },
239    ];
240
241    let mut offset: [usize; 2] = [0, mi.num_subsets * (16 * mi.index_bits[0] - 1)];
242
243    (0..4_usize).for_each(|yy| {
244        (0..4_usize).for_each(|xx| {
245            let idx = yy * 4 + xx;
246
247            let mut subset_index: usize = 0;
248            let mut index_anchor: usize = 0;
249            match mi.num_subsets {
250                2 => {
251                    subset_index = (S_BPTC_P2[partition_set_idx] >> idx) & 1;
252                    index_anchor = if 0 != subset_index {
253                        S_BPTC_A2[partition_set_idx]
254                    } else {
255                        0
256                    };
257                }
258                3 => {
259                    subset_index = (S_BPTC_P3[partition_set_idx] >> (2 * idx)) & 3;
260                    index_anchor = if 0 != subset_index {
261                        S_BPTC_A3[subset_index - 1][partition_set_idx]
262                    } else {
263                        0
264                    };
265                }
266                _ => {}
267            }
268
269            let anchor = idx == index_anchor;
270            let num: [usize; 2] = [
271                (mi.index_bits[0] - anchor as usize),
272                if has_index_bits1 {
273                    mi.index_bits[1] - anchor as usize
274                } else {
275                    0
276                },
277            ];
278
279            let index: [usize; 2] = {
280                let index_0 = bit.peek(offset[0], num[0]) as usize;
281                [
282                    index_0,
283                    if has_index_bits1 {
284                        bit.peek(offset[1], num[1]) as usize
285                    } else {
286                        index_0
287                    },
288                ]
289            };
290
291            offset[0] += num[0];
292            offset[1] += num[1];
293
294            // index selection mode 0 or 1
295            // !index_selection_mode == 1-index_selection_mode
296            let fc: u16 = factors[index_selection_mode][index[index_selection_mode]] as u16;
297            let fa: u16 = factors[1 - index_selection_mode][index[1 - index_selection_mode]] as u16;
298
299            let fca: u16 = 64 - fc;
300            let fcb: u16 = fc;
301            let faa: u16 = 64 - fa;
302            let fab: u16 = fa;
303
304            subset_index *= 2;
305            let mut rr: u8 =
306                ((ep_r[subset_index] as u16 * fca + ep_r[subset_index + 1] as u16 * fcb + 32) >> 6)
307                    as u8;
308            let mut gg: u8 =
309                ((ep_g[subset_index] as u16 * fca + ep_g[subset_index + 1] as u16 * fcb + 32) >> 6)
310                    as u8;
311            let mut bb: u8 =
312                ((ep_b[subset_index] as u16 * fca + ep_b[subset_index + 1] as u16 * fcb + 32) >> 6)
313                    as u8;
314            let mut aa: u8 =
315                ((ep_a[subset_index] as u16 * faa + ep_a[subset_index + 1] as u16 * fab + 32) >> 6)
316                    as u8;
317
318            match rotation_mode {
319                1 => {
320                    swap(&mut aa, &mut rr);
321                }
322                2 => {
323                    swap(&mut aa, &mut gg);
324                }
325                3 => {
326                    swap(&mut aa, &mut bb);
327                }
328                _ => {}
329            }
330            outbuf[idx] = color(rr, gg, bb, aa);
331        });
332    });
333}