j2k-metal
Metal adapter for JPEG 2000 / HTJ2K decode and encode-stage paths on macOS.
The crate provides resident Metal decode and encode-stage integration for
supported workloads. It uses j2k-metal-support for runtime setup while
keeping codec-specific kernels local.
In version 0.9, expert constructors and raw resident handoffs use
objc2-metal protocol objects directly. Pass retained protocol objects for
owned devices, queues, command buffers, and buffers, and borrowed protocol
references where the API does not take ownership. The previous metal-rs
types are intentionally source-incompatible.
Encode support is stage-oriented unless a documented resident path accepts the
shape. For lossless HTJ2K host-output, fixed Auto cells use Metal coefficient
preparation and HT Tier-1 followed by CPU packetization: RGB8 at 1,024 x 1,024
and Gray8/RGB8 at 2,048 x 2,048. The measured 512 x 512 cells and Gray8 at
1,024 x 1,024 stay on CPU. These thresholds apply to supported Metal devices;
the performance evidence is scoped to the measured Apple M4 Pro.
Full resident host-output packetization/assembly is a separate batch path:
batched Gray8 can use it at the 512 x 512 stage gate, while batched RGB8
requires 1,024 x 1,024 or larger resident input. Explicit Metal requests are
strict: supported shapes dispatch, and unsupported direct Metal requests
return UnsupportedMetalRequest instead of silently changing backend.
Metal routing is deliberately selective. Auto may decline small tiles,
irregular packet shapes, or stages where host/device transfer and dispatch
overhead dominate. Stage-by-stage host-output Auto can use deinterleave,
forward RCT/ICT, forward 5/3 and 9/7 DWT, subband quantization, and HT Tier-1
for the qualified cells above. Classic Tier-1, packetization, and codestream
assembly stay CPU for that route unless a documented resident path supports
the shape with parity and benchmark evidence.
Full Resident Encode Path
Use submit_lossless_batch_to_metal when the output should remain a
Metal-backed codestream buffer. This is the full resident contract: coefficient
prep, packetization, and codestream assembly must all report true in
MetalLosslessEncodeResidency before the row is described as a full resident
encode path.
The resident path expects MetalLosslessEncodeTile inputs with
MetalEncodeInputStaging::AlreadyPaddedContiguous for no-copy Metal-buffer
workflows. For supported host-visible outputs, call
submit_lossless_batch(...).wait() to resolve the submission to
Vec<EncodedJ2k>. The hidden encode_lossless_batch_with_report helper is for
internal benchmarking and diagnostics, not the normal application contract.
When collecting benchmark diagnostics, report host readback separately from
resident buffer timing.
Keep benchmark claims scoped: compare resident_host_ms against CPU only when
packetization_used=true, codestream_assembly_used=true, and batch_size > 1.
Treat resident_buffer_ms as device-pipeline context unless the consumer can
keep the codestream buffer resident.
Run the decode route-report example to inspect Auto CPU fallback and strict Metal behavior:
Run the Auto HTJ2K encode report example to inspect final backend selection and per-stage Metal dispatch counts:
Run the resident encode example on macOS to produce a Metal-backed HTJ2K codestream buffer and validate it through the CPU decoder:
Links
- API docs: https://docs.rs/j2k-metal
- Repository: https://github.com/frames-sg/j2k
- Support policy: https://github.com/frames-sg/j2k/blob/main/docs/public-support.md