// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
use num_traits::Float;
use jxl_transforms::{transform::*, transform_map::*};
/// Reset buffers to zero for reuse. pubfn reset(&mutself) { self.scratch.fill(0.0); for buf in &mutself.transform_buffer {
buf.fill(0.0);
} self.coeffs_storage.fill(0);
}
}
let quantized_x = D::I32Vec::load(d, &qblock[0][k..]); let quantized_y = D::I32Vec::load(d, &qblock[1][k..]); let quantized_b = D::I32Vec::load(d, &qblock[2][k..]);
let dequant_x_cc = adjust_quant_bias(d, 0, quantized_x, biases) * x_mul; let dequant_y = adjust_quant_bias(d, 1, quantized_y, biases) * y_mul; let dequant_b_cc = adjust_quant_bias(d, 2, quantized_b, biases) * b_mul;
let dequant_x = D::F32Vec::splat(d, x_cc_mul).mul_add(dequant_y, dequant_x_cc); let dequant_b = D::F32Vec::splat(d, b_cc_mul).mul_add(dequant_y, dequant_b_cc);
dequant_x.store(&mut block[0][k..]);
dequant_y.store(&mut block[1][k..]);
dequant_b.store(&mut block[2][k..]);
}
// Reset and use pooled buffers
buffers.reset(); let scratch = &mut buffers.scratch; let color_correlation_params = lf_global.color_correlation_params.as_ref().unwrap(); let cmap_rect = Rect {
origin: (
block_group_rect.origin.0 / COLOR_TILE_DIM_IN_BLOCKS,
block_group_rect.origin.1 / COLOR_TILE_DIM_IN_BLOCKS,
),
size: (
block_group_rect.size.0.div_ceil(COLOR_TILE_DIM_IN_BLOCKS),
block_group_rect.size.1.div_ceil(COLOR_TILE_DIM_IN_BLOCKS),
),
}; let quant_params = lf_global.quant_params.as_ref().unwrap(); let inv_global_scale = quant_params.inv_global_scale(); let ytox_map = hf_meta.ytox_map.get_rect(cmap_rect); let ytob_map = hf_meta.ytob_map.get_rect(cmap_rect); let transform_map = hf_meta.transform_map.get_rect(block_group_rect); let raw_quant_map = hf_meta.raw_quant_map.get_rect(block_group_rect); let quant_lf_rect = quant_lf.get_rect(block_group_rect); let block_context_map = lf_global.block_context_map.as_mut().unwrap(); // TODO(veluca): improve coefficient storage (smaller allocations, use 16 bits if possible). let coeffs = match hf_global.hf_coefficients.as_mut() {
Some(hf_coefficients) => [
hf_coefficients.0.row_mut(group),
hf_coefficients.1.row_mut(group),
hf_coefficients.2.row_mut(group),
],
None => { // Use pooled buffer (already reset to zero in buffers.reset() above) let (coeffs_x, coeffs_y_b) = buffers.coeffs_storage.split_at_mut(GROUP_DIM * GROUP_DIM); let (coeffs_y, coeffs_b) = coeffs_y_b.split_at_mut(GROUP_DIM * GROUP_DIM);
[coeffs_x, coeffs_y, coeffs_b]
}
}; letmut coeffs_offset = 0; let transform_buffer = &mut buffers.transform_buffer;
let hshift = [
frame_header.hshift(0),
frame_header.hshift(1),
frame_header.hshift(2),
]; let vshift = [
frame_header.vshift(0),
frame_header.vshift(1),
frame_header.vshift(2),
]; let lf = match lf_image.as_ref() {
None => None,
Some(lf_planes) => { let r: [Rect; 3] = core::array::from_fn(|i| Rect {
origin: (
block_group_rect.origin.0 >> hshift[i],
block_group_rect.origin.1 >> vshift[i],
),
size: (
block_group_rect.size.0 >> hshift[i],
block_group_rect.size.1 >> vshift[i],
),
});
let [lf_x, lf_y, lf_b] = lf_planes.each_ref();
Some([
lf_x.get_rect(r[0]),
lf_y.get_rect(r[1]),
lf_b.get_rect(r[2]),
])
}
}; for by in0..block_group_rect.size.1 { let sby = [by >> vshift[0], by >> vshift[1], by >> vshift[2]]; let ty = by / COLOR_TILE_DIM_IN_BLOCKS;
let row_cmap_x = ytox_map.row(ty); let row_cmap_b = ytob_map.row(ty);
for bx in0..block_group_rect.size.0 { let sbx = [bx >> hshift[0], bx >> hshift[1], bx >> hshift[2]]; let tx = bx / COLOR_TILE_DIM_IN_BLOCKS; let x_cc_mul = color_correlation_params.y_to_x(row_cmap_x[tx] as i32); let b_cc_mul = color_correlation_params.y_to_b(row_cmap_b[tx] as i32); let raw_quant = raw_quant_map.row(by)[bx] as u32; let quant_lf = quant_lf_rect.row(by)[bx] as usize; let raw_transform_id = transform_map.row(by)[bx]; let transform_id = raw_transform_id & 127; let is_first_block = raw_transform_id >= 128; if !is_first_block { continue;
} let lf_rects = match lf.as_ref() {
None => None,
Some(lf) => { let [lf_x, lf_y, lf_b] = lf.each_ref();
Some([
lf_x.rect(Rect {
origin: (sbx[0], sby[0]),
size: (lf_x.size().0 - sbx[0], lf_x.size().1 - sby[0]),
}),
lf_y.rect(Rect {
origin: (sbx[1], sby[1]),
size: (lf_y.size().0 - sbx[1], lf_y.size().1 - sby[1]),
}),
lf_b.rect(Rect {
origin: (sbx[2], sby[2]),
size: (lf_b.size().0 - sbx[2], lf_b.size().1 - sby[2]),
}),
])
}
};
let transform_type = HfTransformType::from_usize(transform_id as usize)
.ok_or(Error::InvalidVarDCTTransform(transform_id as usize))?; let cx = covered_blocks_x(transform_type) as usize; let cy = covered_blocks_y(transform_type) as usize; let shape_id = block_shape_id(transform_type) as usize; let block_size = (cx * BLOCK_DIM, cy * BLOCK_DIM); let block_rect = Rect {
origin: (bx * BLOCK_DIM, by * BLOCK_DIM),
size: block_size,
}; let num_blocks = cx * cy; let num_coeffs = num_blocks * BLOCK_SIZE; let log_num_blocks = num_blocks.ilog2() as usize; for PassInfo {
histogram_index,
reader,
br,
shift,
pass,
num_nzeros,
} in pass_info.iter_mut()
{ let reader = reader.as_mut().unwrap(); let pass_info = &hf_global.passes[*pass]; let context_offset = *histogram_index * block_context_map.num_ac_contexts(); for c in [1, 0, 2] { if (sbx[c] << hshift[c]) != bx || (sby[c] << vshift[c] != by) { continue;
}
trace!( "Decoding block ({},{}) channel {} with {}x{} block transform {} (shape id {})",
sbx[c], sby[c], c, cx, cy, transform_id, shape_id
); let predicted_nzeros = predict_num_nonzeros(&num_nzeros[c], sbx[c], sby[c]); let block_context =
block_context_map.block_context(quant_lf, raw_quant, shape_id, c); let nonzero_context = block_context_map
.nonzero_context(predicted_nzeros, block_context)
+ context_offset; letmut nonzeros =
reader.read_unsigned_inline(&pass_info.histograms, br, nonzero_context) as usize;
trace!( "block ({},{},{c}) predicted_nzeros: {predicted_nzeros} \
nzero_ctx: {nonzero_context} (offset: {context_offset}) \
nzeros: {nonzeros}",
sbx[c], sby[c]
); if nonzeros + num_blocks > num_coeffs { return Err(Error::InvalidNumNonZeros(nonzeros, num_blocks));
} for iy in0..cy { let nzrow = num_nzeros[c].row_mut(sby[c] + iy); for ix in0..cx {
nzrow[sbx[c] + ix] = nonzeros.shrc(log_num_blocks) as u32;
}
} let histo_offset = block_context_map.zero_density_context_offset(block_context)
+ context_offset; letmut prev = if nonzeros > num_coeffs / 16 { 0 } else { 1 }; let permutation = &pass_info.coeff_orders[shape_id * 3 + c]; let current_coeffs = &mut coeffs[c][coeffs_offset..coeffs_offset + num_coeffs]; for k in num_blocks..num_coeffs { if nonzeros == 0 { break;
} let ctx =
histo_offset + zero_density_context(nonzeros, k, log_num_blocks, prev); let coeff =
reader.read_signed_inline(&pass_info.histograms, br, ctx) << *shift;
prev = if coeff != 0 { 1 } else { 0 };
nonzeros -= prev; let coeff_index = permutation[k] as usize;
current_coeffs[coeff_index] += coeff;
} if nonzeros != 0 { return Err(Error::EndOfBlockResidualNonZeros(nonzeros));
}
}
} iflet Some(pixels) = pixels { let qblock = [
&coeffs[0][coeffs_offset..],
&coeffs[1][coeffs_offset..],
&coeffs[2][coeffs_offset..],
]; let dequant_matrices = &hf_global.dequant_matrices;
dequant_and_transform_to_pixels_dispatch(
quant_biases,
x_dm_multiplier,
b_dm_multiplier,
pixels,
scratch,
inv_global_scale,
transform_buffer,
hshift,
vshift,
by,
sby,
bx,
sbx,
x_cc_mul,
b_cc_mul,
raw_quant,
&lf_rects,
transform_type,
block_rect,
num_blocks,
num_coeffs,
&qblock,
dequant_matrices,
)?;
}
coeffs_offset += num_coeffs;
}
} for PassInfo {
pass, br, reader, ..
} in pass_info.iter_mut()
{
std::mem::take(reader)
.unwrap()
.check_final_state(&hf_global.passes[*pass].histograms, br)?;
}
Ok(())
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.