Skip to main content

otf_pixels_ops/
lib.rs

1//! Operation kernels for `otf-pixels`.
2//!
3//! Each op implements [`Op`] and is chained onto an
4//! [`Image`] to build graph structure. Ops do no work when chained — they
5//! declare their output shape and their demand, and run only when a terminal
6//! pulls pixels through them.
7//!
8//! [`Op`]: otf_pixels_core::Op
9//! [`Image`]: otf_pixels_core::Image
10//!
11//! # Scope
12//!
13//! The full v1 op set from SPEC §Core ops is here: [`Resize`], [`Crop`],
14//! [`Rotate`], [`Flip`], [`Flop`], [`Modulate`], [`Convolve`], [`Composite`],
15//! [`ExtractChannel`] and [`Flatten`].
16//!
17//! # Two kinds of op
18//!
19//! **Layout** ops — crop, flip, flop, rotate — move whole pixels without
20//! inspecting them. They copy opaque byte runs, so one implementation is
21//! correct for every pixel format including ones added later, and they do not
22//! use `dispatch_sample!`: there is no arithmetic to specialize.
23//!
24//! **Arithmetic** ops — resize, modulate, convolve, composite, flatten — read
25//! sample values, so they dispatch once per tile on the sample type and run a
26//! monomorphized inner loop (ADR-0002). Per ADR-0011 those loops are written
27//! to autovectorize rather than to call intrinsics, and 8-bit paths use `i32`
28//! fixed point so that vectorization cannot change the result.
29//!
30//! # Tiling is not observable
31//!
32//! Every op here produces the same pixels whether it runs in one tile or in
33//! many. That is not automatic — a resize whose weight tables were built per
34//! tile would resample at the tile's scale — so each op with a non-trivial
35//! demand mapping asserts it directly.
36//!
37//! # Writing an op
38//!
39//! An op declares four things (ARCHITECTURE §Layer 3):
40//!
41//! - `output_descriptor` — its output shape, computed at graph-build time.
42//! - `input_regions` — the inverse mapping demand propagation walks backwards.
43//! - `access_pattern` — `Sequential` or `Spatial`, driving tile negotiation
44//!   (ADR-0003).
45//! - `compute` — the kernel itself.
46//!
47//! The first three are what make an op work correctly under M2's scheduler
48//! rather than only under M1's whole-image evaluator, so they must be right
49//! even while the evaluator only ever asks for whole images.
50
51mod composite;
52mod convert;
53mod convolve;
54mod filter;
55mod geometry;
56mod icc;
57mod pointwise;
58mod resample;
59mod resize;
60mod rotate;
61
62pub use composite::{Blend, Composite};
63pub use convert::ConvertFormat;
64pub use convolve::{Convolve, Kernel};
65pub use filter::{Filter, Run, Weights};
66pub use geometry::{Crop, Flip, Flop};
67pub use icc::{Conversion, ToSrgb, Unconvertible};
68pub use pointwise::{ExtractChannel, Flatten, Modulate};
69pub use resize::{Fit, Resize, ResizeOptions};
70pub use rotate::{Quarter, Rotate};