use j2k_core::try_host_vec_with_capacity;
#[cfg(target_os = "macos")]
use super::budget::metal_sparse_weight_budget;
use super::{
budget::bounded_sparse_weight_budget,
error::allocation_error,
shared::{high_len, low_len, WaveletBand, WaveletKind},
symbolic::write_symbolic_row,
SparseWeightRowsError,
};
#[derive(Debug, Clone, PartialEq)]
pub struct SparseDwt97WeightRows {
pub low: Vec<SparseWeightRow>,
pub high: Vec<SparseWeightRow>,
}
impl SparseDwt97WeightRows {
pub fn for_len(sample_len: usize) -> Result<Self, SparseWeightRowsError> {
let rows = sparse_rows_for_len(sample_len, WaveletKind::Irreversible97)?;
Ok(Self {
low: rows.low,
high: rows.high,
})
}
#[cfg(target_os = "macos")]
pub(crate) fn allocation_bytes_for_len(
sample_len: usize,
) -> Result<usize, SparseWeightRowsError> {
sparse_allocation_bytes(sample_len, WaveletKind::Irreversible97)
}
#[cfg(target_os = "macos")]
pub(crate) fn metal_bytes_for_len(sample_len: usize) -> Result<usize, SparseWeightRowsError> {
sparse_metal_bytes(sample_len, WaveletKind::Irreversible97)
}
#[must_use]
pub fn max_taps_per_row(&self) -> usize {
max_taps_per_row(&self.low, &self.high)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SparseDwt53WeightRows {
pub low: Vec<SparseWeightRow>,
pub high: Vec<SparseWeightRow>,
}
impl SparseDwt53WeightRows {
pub fn for_len(sample_len: usize) -> Result<Self, SparseWeightRowsError> {
let rows = sparse_rows_for_len(sample_len, WaveletKind::Reversible53)?;
Ok(Self {
low: rows.low,
high: rows.high,
})
}
#[cfg(target_os = "macos")]
pub(crate) fn allocation_bytes_for_len(
sample_len: usize,
) -> Result<usize, SparseWeightRowsError> {
sparse_allocation_bytes(sample_len, WaveletKind::Reversible53)
}
#[cfg(target_os = "macos")]
pub(crate) fn metal_bytes_for_len(sample_len: usize) -> Result<usize, SparseWeightRowsError> {
sparse_metal_bytes(sample_len, WaveletKind::Reversible53)
}
#[must_use]
pub fn max_taps_per_row(&self) -> usize {
max_taps_per_row(&self.low, &self.high)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SparseWeightRow {
pub taps: Vec<SparseWeightTap>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SparseWeightTap {
pub sample_idx: usize,
pub weight: f32,
}
struct SparseRows {
low: Vec<SparseWeightRow>,
high: Vec<SparseWeightRow>,
}
fn sparse_rows_for_len(
sample_len: usize,
wavelet: WaveletKind,
) -> Result<SparseRows, SparseWeightRowsError> {
let max_taps = wavelet.max_taps_per_row();
bounded_sparse_weight_budget(sample_len, max_taps)?;
let mut low = empty_sparse_rows(low_len(sample_len), max_taps)?;
let mut high = empty_sparse_rows(high_len(sample_len), max_taps)?;
for (output_idx, row) in low.iter_mut().enumerate() {
write_symbolic_row(row, sample_len, output_idx, WaveletBand::Low, wavelet)?;
}
for (output_idx, row) in high.iter_mut().enumerate() {
write_symbolic_row(row, sample_len, output_idx, WaveletBand::High, wavelet)?;
}
Ok(SparseRows { low, high })
}
fn empty_sparse_rows(
count: usize,
max_taps_per_row: usize,
) -> Result<Vec<SparseWeightRow>, SparseWeightRowsError> {
let mut rows = try_host_vec_with_capacity(count).map_err(allocation_error)?;
for _ in 0..count {
rows.push(SparseWeightRow {
taps: try_host_vec_with_capacity(max_taps_per_row).map_err(allocation_error)?,
});
}
Ok(rows)
}
#[cfg(target_os = "macos")]
fn sparse_allocation_bytes(
sample_len: usize,
wavelet: WaveletKind,
) -> Result<usize, SparseWeightRowsError> {
bounded_sparse_weight_budget(sample_len, wavelet.max_taps_per_row())
}
#[cfg(target_os = "macos")]
fn sparse_metal_bytes(
sample_len: usize,
wavelet: WaveletKind,
) -> Result<usize, SparseWeightRowsError> {
metal_sparse_weight_budget(sample_len, wavelet.max_taps_per_row())
}
fn max_taps_per_row(low: &[SparseWeightRow], high: &[SparseWeightRow]) -> usize {
low.iter()
.chain(high)
.map(|row| row.taps.len())
.max()
.unwrap_or(0)
}