use super::tables::{ASTC_CFG_TABLE, TOTAL_UNIQUE_PATTERNS, UNIQUE_INDEX_TO_PART_SEED};
use crate::once::OnceBox;
use alloc::boxed::Box;
use alloc::vec::Vec;
pub const ASTC_BLOCK_SIZES: [(u32, u32); 14] = [
(4, 4),
(5, 4),
(5, 5),
(6, 5),
(6, 6),
(8, 5),
(8, 6),
(10, 5),
(10, 6),
(8, 8),
(10, 8),
(10, 10),
(12, 10),
(12, 12),
];
pub fn block_size_index(w: u32, h: u32) -> Option<usize> {
ASTC_BLOCK_SIZES.iter().position(|&d| d == (w, h))
}
#[derive(Clone, Copy)]
pub struct TrialMode {
pub cem: u32,
pub num_parts: u32,
pub ccs_index: i32,
pub weight_ise_range: u32,
pub endpoint_ise_range: u32,
pub grid_width: u32,
pub grid_height: u32,
}
pub struct BlockSizeModes {
pub modes: Vec<TrialMode>,
groups: Vec<Vec<u32>>,
}
const OTM_NUM_CEMS: usize = 14;
const OTM_NUM_SUBSETS: usize = 3;
const OTM_NUM_CCS: usize = 5;
const OTM_NUM_GRID_SIZES: usize = 2;
const OTM_NUM_GRID_ANISOS: usize = 3;
#[inline]
fn group_index(cem: usize, subsets: usize, ccs: usize, grid_size: usize, aniso: usize) -> usize {
(((cem * OTM_NUM_SUBSETS + subsets) * OTM_NUM_CCS + ccs) * OTM_NUM_GRID_SIZES + grid_size)
* OTM_NUM_GRID_ANISOS
+ aniso
}
#[inline]
pub fn calc_grid_aniso_val(gw: u32, gh: u32, bw: u32, bh: u32) -> usize {
let lhs = gw * bh;
let rhs = gh * bw;
if lhs == rhs {
0
} else if lhs >= rhs {
1
} else {
2
}
}
impl BlockSizeModes {
pub fn tm_candidates(
&self,
cem_index: u32,
subset_index: u32,
ccs_index: u32,
grid_size: u32,
grid_aniso: u32,
) -> &[u32] {
&self.groups[group_index(
cem_index as usize,
subset_index as usize,
ccs_index as usize,
grid_size as usize,
grid_aniso as usize,
)]
}
}
const UNIQUE_LDR_INDEX_TO_CEM: [u32; 6] = [0, 4, 6, 8, 10, 12];
fn build(bw: u32, bh: u32) -> BlockSizeModes {
let mut modes = Vec::with_capacity(3072);
let mut groups = alloc::vec![Vec::new(); OTM_NUM_CEMS * OTM_NUM_SUBSETS * OTM_NUM_CCS * OTM_NUM_GRID_SIZES
* OTM_NUM_GRID_ANISOS];
for &packed in ASTC_CFG_TABLE.iter() {
let mut p = packed;
let mut take = |bits: u32| {
let v = p & ((1 << bits) - 1);
p >>= bits;
v
};
let endpoint_ise_range = take(5);
let weight_ise_range = take(4);
let ccs_index = take(3);
let num_subsets = take(2);
let unique_cem_index = take(3);
let grid_wh = take(7);
let grid_width = grid_wh / 11 + 2;
if grid_width > bw {
break;
}
let grid_height = grid_wh % 11 + 2;
if grid_height > bh {
continue;
}
let tm = TrialMode {
cem: UNIQUE_LDR_INDEX_TO_CEM[unique_cem_index as usize],
num_parts: num_subsets + 1,
ccs_index: ccs_index as i32 - 1,
weight_ise_range,
endpoint_ise_range: endpoint_ise_range + 4,
grid_width,
grid_height,
};
let tm_index = modes.len() as u32;
let grid_size = usize::from(tm.grid_width >= bw - 1 && tm.grid_height >= bh - 1);
let aniso = calc_grid_aniso_val(tm.grid_width, tm.grid_height, bw, bh);
groups[group_index(
tm.cem as usize,
(tm.num_parts - 1) as usize,
(tm.ccs_index + 1) as usize,
grid_size,
aniso,
)]
.push(tm_index);
modes.push(tm);
}
BlockSizeModes { modes, groups }
}
pub fn block_size_modes(block_size_index: usize) -> &'static BlockSizeModes {
static TABLES: OnceBox<[BlockSizeModes; 14]> = OnceBox::new();
&TABLES.get_or_init(|| {
Box::new(core::array::from_fn(|i| {
let (bw, bh) = ASTC_BLOCK_SIZES[i];
build(bw, bh)
}))
})[block_size_index]
}
#[inline]
pub fn total_unique_patterns(block_size_index: usize, num_parts: u32) -> u32 {
TOTAL_UNIQUE_PATTERNS[block_size_index][(num_parts - 2) as usize] as u32
}
#[inline]
pub fn unique_pat_index_to_part_seed(
block_size_index: usize,
num_parts: u32,
unique_pat_index: u32,
) -> u16 {
UNIQUE_INDEX_TO_PART_SEED[(num_parts - 2) as usize][block_size_index][unique_pat_index as usize]
}