pub struct ConvertPlan { /* private fields */ }Expand description
Pre-computed conversion plan.
Stores the chain of steps needed to convert from one format to another. Created once, applied to every row.
Implementations§
Source§impl ConvertPlan
impl ConvertPlan
Sourcepub fn new(
from: PixelDescriptor,
to: PixelDescriptor,
) -> Result<Self, At<ConvertError>>
pub fn new( from: PixelDescriptor, to: PixelDescriptor, ) -> Result<Self, At<ConvertError>>
Create a conversion plan from from to to.
Returns Err if no conversion path exists. A
SignalRange mismatch always refuses
(ConvertError::NoPath): there are no Narrow↔Full conversion
kernels, and relabeling without rescaling would corrupt pixels — see
the signal-range notes on the crate docs.
CMYK (and any other non-native color model) returns
ConvertError::NeedsCms so the caller can re-issue via
RowConverter::new_explicit_with_cms
with a PluggableCms backend attached.
ConvertPlan itself never dispatches through CMS — wire the call
through RowConverter for that.
Sourcepub fn new_with_hdr_peak(
from: PixelDescriptor,
to: PixelDescriptor,
source_peak_nits: f32,
) -> Result<Self, At<ConvertError>>
pub fn new_with_hdr_peak( from: PixelDescriptor, to: PixelDescriptor, source_peak_nits: f32, ) -> Result<Self, At<ConvertError>>
Create an HDR→SDR conversion plan with the given source-peak luminance.
Equivalent to ConvertPlan::new_with_hdr_config called with
HdrConfig::for_source_peak(source_peak_nits)
(target_peak_nits = 100.0, gamut_knee = 0.96).
The plan inserts a Bt2446A tone-map step
(and an OKLch soft-compress step for non-BT.2020 targets) into the
usual transfer / depth / gamut chain. Non-HDR conversions go through
the same path as ConvertPlan::new.
§Errors
Same as ConvertPlan::new for non-HDR conversions.
HdrSourceRequiresPeak is raised only when source_peak_nits
is not a positive, finite number — a supplied-but-degenerate peak
would otherwise tone-map every pixel to black.
§Panics
Same panics as ConvertPlan::new (CMYK descriptors).
Sourcepub fn new_with_hdr_config(
from: PixelDescriptor,
to: PixelDescriptor,
hdr: HdrConfig,
) -> Result<Self, At<ConvertError>>
pub fn new_with_hdr_config( from: PixelDescriptor, to: PixelDescriptor, hdr: HdrConfig, ) -> Result<Self, At<ConvertError>>
Create an HDR→SDR conversion plan with full knob control.
On HDR→SDR conversions (Pq / Hlg source → SDR target, OR a
Linear source where the caller declares HDR semantics via this
constructor) inserts:
- HDR transfer decode (PQ/HLG → linear) — same kernels as
ConvertPlan::new. Skipped when the source is alreadyLinear. - Source primaries → BT.2020 matrix (skipped when source is BT.2020).
ToneMapBt2446Astep (the BT.2446 Method A curve operating in BT.2020 RGB).- BT.2020 → target primaries matrix (skipped when target is BT.2020).
SoftCompressOklchstep (skipped when target is BT.2020 — wide-gamut output mode preserves chroma).- Linear → target transfer encode + any depth conversion (sRGB u8,
BT.1886 f32, etc.) — same kernels as
ConvertPlan::new.
For sources that are obviously SDR (Srgb / Bt709 / Gamma22)
the hdr argument is ignored and this returns the same plan
ConvertPlan::new would build — no tone-map gets injected into
a path that doesn’t need one.
§Errors
Same as ConvertPlan::new for non-HDR conversions. For HDR
sources, HdrSourceRequiresPeak is raised when
hdr.source_peak_nits or hdr.target_peak_nits is not a
positive, finite number (including the unset
HdrConfig::default value 0.0) — degenerate peaks would
otherwise flow into the BT.2446-A constants as inf/NaN and the
kernel’s NaN scrub would silently emit an all-black image.
CMYK (and any other non-native color model) returns
ConvertError::NeedsCms — same posture as
ConvertPlan::new. HDR tone-mapping is RGB-only; a CMS is the
right tool for CMYK↔RGB even on the HDR construction path.
Sourcepub fn new_explicit(
from: PixelDescriptor,
to: PixelDescriptor,
options: &ConvertOptions,
) -> Result<Self, At<ConvertError>>
pub fn new_explicit( from: PixelDescriptor, to: PixelDescriptor, options: &ConvertOptions, ) -> Result<Self, At<ConvertError>>
Create a conversion plan with explicit policy enforcement.
Validates that the planned conversion steps are allowed by the given policies before creating the plan. Returns an error if a forbidden operation would be required.
CMYK (and any other non-native color model) returns
ConvertError::NeedsCms — same posture as
ConvertPlan::new. To dispatch CMYK ↔ RGB through a CMS, build
the converter via
RowConverter::new_explicit_with_cms
with a PluggableCms plugin attached.
Sourcepub fn compose(&self, other: &Self) -> Option<Self>
pub fn compose(&self, other: &Self) -> Option<Self>
Compose two plans into one: apply self then other.
The composed plan executes both conversions in a single convert_row
call, using one intermediate buffer instead of two. Adjacent inverse
steps are cancelled (e.g., SrgbU8ToLinearF32 + LinearF32ToSrgbU8
→ identity).
Returns None if self.to != other.from (incompatible plans).
Sourcepub fn is_identity(&self) -> bool
pub fn is_identity(&self) -> bool
True if conversion is a no-op.
Sourcepub fn from(&self) -> PixelDescriptor
pub fn from(&self) -> PixelDescriptor
Source descriptor.
Sourcepub fn to(&self) -> PixelDescriptor
pub fn to(&self) -> PixelDescriptor
Target descriptor.
Sourcepub fn estimate_in(
&self,
image: &ImageCharacteristics,
compute: &ComputeEnvironment,
) -> ResourceEstimate
pub fn estimate_in( &self, image: &ImageCharacteristics, compute: &ComputeEnvironment, ) -> ResourceEstimate
Estimate resources for executing this plan on image under the
given ComputeEnvironment.
Returns a ResourceEstimate
whose type shape matches zencodec::estimate::ResourceEstimate so
codec-side encode/decode estimates can be wired through a multi-
stage pipeline at the codec boundary with a trivial conversion.
Calibrated from benches/t1_layout, t2_depth, t3_tf_fused,
t4_tf_f32, t5_alpha, t6_oklab, t7_gamut steady-state
throughput; best-effort, ±30 % on the reference machine
(Ryzen 9 7950X, AVX2). Real wall time varies with contention,
frequency scaling, and CPU model. Identity at 0×0 returns a
zero-cost estimate.
peak_memory_bytes_est is the destination buffer plus row-sized
ping-pong scratch (multi-step plans). It does NOT include the
caller’s persistent state. intermediate_buffer_count reports the
number of full-image intermediate buffers held simultaneously
(0 for identity / single-step plans; 2 for multi-step plans using
ping-pong scratch) so schedulers can distinguish 1-giant-buffer plans
from N-medium-buffer plans for paging-pressure decisions.
wall_ms is divided down by compute.cores() via the plan’s
internal threading-bottleneck model (see the estimate module
docs): any SERIAL step forces the whole plan SERIAL; otherwise the
smallest per-step knee — rows / 64 clamped to [1, 16] — caps
the useful thread count.
compute.simd_tier() applies a coarse per-tier wall-time
multiplier on top of the AVX2 baseline (see the estimate
module docs for the per-tier ratios; TODO per-tier calibration).
Cheap to call — walks the plan’s steps once and does no allocation. Safe to call repeatedly per-frame in throttled pipelines.
For a quick estimate using ComputeEnvironment::new()
defaults on a width × height image, see estimate.
§Example
use zenpixels::PixelDescriptor;
use zenpixels_convert::{ComputeEnvironment, ConvertPlan, ImageCharacteristics};
let plan = ConvertPlan::new(
PixelDescriptor::RGB8_SRGB,
PixelDescriptor::RGBA8_SRGB,
).unwrap();
let image = ImageCharacteristics::new(1920, 1080, PixelDescriptor::RGB8_SRGB);
let compute = ComputeEnvironment::new().with_cores(8);
let est = plan.estimate_in(&image, &compute);
assert!(est.peak_memory_bytes_est().unwrap_or(0) > 0);
// wall_ms is `Some(_)` once the plan has measurable work (it can
// round to 0 ms for trivial plans, but the field is populated).
assert!(est.wall_ms().is_some());Sourcepub fn estimate(&self, width: u32, height: u32) -> ResourceEstimate
pub fn estimate(&self, width: u32, height: u32) -> ResourceEstimate
Shortcut: estimate with ComputeEnvironment::new()
defaults (single core, unknown RAM, unspecified SIMD tier) on a
width × height image. Builds the
ImageCharacteristics from
the plan’s from() descriptor and calls estimate_in.
Use estimate_in directly when the caller has
a populated compute environment (e.g.
available_parallelism() + archmage tier).
§Example
use zenpixels::PixelDescriptor;
use zenpixels_convert::ConvertPlan;
let plan = ConvertPlan::new(
PixelDescriptor::RGB8_SRGB,
PixelDescriptor::RGBA8_SRGB,
).unwrap();
let est = plan.estimate(1920, 1080);
assert!(est.peak_memory_bytes_est().unwrap_or(0) > 0);
assert!(est.wall_ms().is_some());Trait Implementations§
Source§impl Clone for ConvertPlan
impl Clone for ConvertPlan
Source§fn clone(&self) -> ConvertPlan
fn clone(&self) -> ConvertPlan
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more