Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ and stale roadmap entries have been removed from the public documentation set.

## [Unreleased]

- `CpuBatchDecoder` region and region-plus-reduced requests no longer
allocate coefficient and IDWT buffers for whole resolution levels
([#299](https://github.com/frames-sg/j2k/issues/299)). Preparation keeps
the shared whole-level plan that Metal and CUDA execute, and adds a CPU copy
whose sub-bands and IDWT levels hold only what the region's stores read,
with the windows native region decode uses. On an 18000 x 12000 RGB image,
1024 px tiles at full and half resolution failed with `ImageTooLarge`; they
now decode with output identical to single-image region decode. Quarter
resolution, which already fit, takes 24 ms instead of 48 ms for four HTJ2K
tiles and 310 to 317 ms instead of 343 to 346 ms for classic. The CPU uses
the copy only when it at least halves the plan's coefficients or the
whole-level plan holds 16 Mi coefficients or more, because the windowed
IDWT is slower per sample than the banded whole-level one; full and reduced
requests, and regions covering most of a small image, are unchanged. See
`docs/benchmark-evidence.md`.
- Owned-batch preparation no longer fails with "failed to decode code-block"
on reduced-resolution regions that end where a tile begins on the reduced
grid ([#298](https://github.com/frames-sg/j2k/issues/298)). Tile selection
rounds tile bounds outward, so it can keep a boundary tile that contributes
no samples; the referenced plan builders rejected such a tile and now leave
it out. This affected the CPU and Metal batches alike. On the 19 x 13
OpenJPH fixture in 11 x 7 tiles, 4,598 of the 17,290 half-scale regions
failed to prepare; all now match single-image decode.
- `j2k-tilecodec` LZW decode no longer reports valid TIFF strips and tiles
as truncated. weezl reads input ahead of decoding, so the call that
consumes the last byte can still hold codes up to the end code, often in
Expand Down
43 changes: 43 additions & 0 deletions crates/j2k-metal/src/batch_decoder/region_group_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,46 @@ fn local_large_region_batch_characterization() {
}
}
}

#[test]
fn reduced_regions_ending_at_rounded_tile_edges_match_the_cpu() {
// 19 x 13 OpenJPH images in 11 x 7 tiles: these regions end where a tile
// begins on the reduced grid, so tile selection keeps a tile that
// contributes no samples.
if !j2k_test_support::metal_runtime_gate(module_path!()) {
return;
}
let regions = [
(0, 0, 11, 1),
(0, 0, 11, 7),
(0, 0, 19, 7),
(10, 6, 2, 2),
(11, 7, 8, 6),
];
for fixture in j2k_test_support::openjph_batch_fixtures()
.iter()
.filter(|fixture| fixture.precision == 8 && !fixture.signed)
{
let bytes = Arc::<[u8]>::from(fixture.encoded);
let inputs: Vec<_> = [Downscale::Half, Downscale::Quarter]
.into_iter()
.flat_map(|scale| {
regions
.iter()
.map(move |&(x, y, w, h)| (Rect { x, y, w, h }, scale))
})
.map(|(roi, scale)| EncodedImage::new(bytes.clone(), request(roi, scale)))
.collect();
let mut decoder =
MetalBatchDecoder::system_default_with_options(options()).expect("decoder");
let expected = cpu_images(&inputs);
let actual = metal_images(&mut decoder, &inputs);
for (index, (actual, expected)) in actual.iter().zip(&expected).enumerate() {
assert!(
actual == expected,
"{} request {index} differs from CPU",
fixture.name
);
}
}
}
5 changes: 5 additions & 0 deletions crates/j2k-native/src/direct_roi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ impl From<J2kRequiredBandRegion> for J2kRect {
#[cfg(test)]
mod region_tests;

mod plan_windows;
pub use plan_windows::{
window_referenced_classic_plan_to_stores, window_referenced_htj2k_plan_to_stores,
};

/// Required input windows for one direct-plan IDWT step.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct J2kIdwtRequiredInputWindows {
Expand Down
Loading
Loading