Skip to content

Commit

Permalink
Draft interface for a render pipeline.
Browse files Browse the repository at this point in the history
  • Loading branch information
veluca93 committed Sep 19, 2024
1 parent 3898382 commit 721ed95
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
1 change: 1 addition & 0 deletions jxl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ pub mod error;
pub mod headers;
pub mod icc;
pub mod image;
pub mod render;
mod util;
106 changes: 106 additions & 0 deletions jxl/src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::{
error::Result,
image::{ImageDataType, ImageRectMut},
};

// All *_row_chunk functions here take one or two slices of slices.
// The slices have as many entries as the number of used channels for the stage, i.e. the channels
// for which `uses_channel` returns true.

// These are the only stages that are assumed to have observable effects, i.e. calls to process_row
// for other stages may be omitted if it can be shown they can't affect any Input stage process_row
// call that happens inside image boundaries.
pub trait RenderPipelineInputStage<InputT: ImageDataType> {
fn uses_channel(&self, c: usize) -> bool;
fn process_row_chunk(&mut self, position: (usize, usize), xsize: usize, row: &[&[InputT]]);
}

// Modifies channels in-place.
pub trait RenderPipelineInPlaceStage<T: ImageDataType> {
fn uses_channel(&self, c: usize) -> bool;
fn process_row_chunk(&mut self, position: (usize, usize), xsize: usize, row: &mut [&mut [T]]);
}

// Modifies data and writes it to a new buffer, of possibly different type.
pub trait RenderPipelineInOutStage<InputT: ImageDataType, OutputT: ImageDataType> {
// Amount of padding required on the input side.
const BORDER: (usize, usize);
// log2 of the number of rows/columns produced for each row/column of input.
const SHIFT: (usize, usize);

fn uses_channel(&self, c: usize) -> bool;

// For each channel:
// - the input slice contains 1 + Self::BORDER.1 * 2 slices, each of length
// xsize + Self::BORDER.0 * 2, i.e. covering one input row and up to BORDER pixels of
// padding on either side.
// - the output slice contains 1 << SHIFT.1 slices, each of length xsize << SHIFT.0, the
// corresponding output pixels.
fn process_row_chunk(
&mut self,
position: (usize, usize),
xsize: usize,
input: &[&[&[InputT]]],
output: &mut [&mut [&mut [OutputT]]],
);
}

// Does not directly modify the current image pixels, but extends the current image with
// additional data.
pub trait RenderPipelineExtendStage<T: ImageDataType> {
// uses_channel is assumed to be always true
fn new_size(&self) -> (usize, usize);
fn original_data_origin(&self) -> (usize, usize);
// passed buffer must always be entirely outside of the original image.
fn fill_padding_row_chunk(
&mut self,
new_position: (usize, usize),
xsize: usize,
row: &mut [&mut [T]],
);
}

pub trait RenderPipelineBuilder: Sized {
type RenderPipeline: RenderPipeline;

fn new(num_channels: usize, size: (usize, usize), group_size: usize) -> Self;

fn add_input_stage<T: ImageDataType, Stage: RenderPipelineInputStage<T>>(
self,
stage: Stage,
) -> Result<Self>;

fn add_inplace_stage<T: ImageDataType, Stage: RenderPipelineInPlaceStage<T>>(
self,
stage: Stage,
) -> Result<Self>;

fn add_inout_stage<
InT: ImageDataType,
OutT: ImageDataType,
Stage: RenderPipelineInOutStage<InT, OutT>,
>(
self,
stage: Stage,
) -> Result<Self>;

fn add_extend_stage<T: ImageDataType, Stage: RenderPipelineExtendStage<T>>(
self,
stage: Stage,
) -> Result<Self>;

fn build(self) -> Self::RenderPipeline;
}

pub trait RenderPipeline {
type Builder: RenderPipelineBuilder<RenderPipeline = Self>;

// TODO(veluca): figure out a good multithreaded interface.
fn fill_group_input<T: ImageDataType, F: FnMut(ImageRectMut<T>, usize) -> bool>(
&mut self,
_group_id: usize,
_do_fill_group: F,
) {
todo!()
}
}

0 comments on commit 721ed95

Please sign in to comment.