mod immediate; mod multithreaded; #[cfg(all( not(any(target_arch = "asmjs", target_arch = "wasm32")), feature = "rayon" ))] mod rayon; use crate::decoder::{choose_color_convert_func, ColorTransform}; use crate::error::Result; use crate::parser::{Component, Dimensions}; use crate::upsampler::Upsampler; use alloc::sync::Arc; use alloc::vec::Vec; use core::cell::RefCell; pub struct RowData { pub index: usize, pub component: Component, pub quantization_table: Arc<[u16; 64]>, } pub trait Worker { fn start(&mut self, row_data: RowData) -> Result<()>; fn append_row(&mut self, row: (usize, Vec)) -> Result<()>; fn get_result(&mut self, index: usize) -> Result>; /// Default implementation for spawning multiple tasks. fn append_rows(&mut self, row: &mut dyn Iterator)>) -> Result<()> { for item in row { self.append_row(item)?; } Ok(()) } } #[allow(dead_code)] pub enum PreferWorkerKind { Immediate, Multithreaded, } #[derive(Default)] pub struct WorkerScope { inner: core::cell::RefCell>, } enum WorkerScopeInner { #[cfg(all( not(any(target_arch = "asmjs", target_arch = "wasm32")), feature = "rayon" ))] Rayon(rayon::Scoped), #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] Multithreaded(multithreaded::MpscWorker), Immediate(immediate::ImmediateWorker), } impl WorkerScope { pub fn with(with: impl FnOnce(&Self) -> T) -> T { with(&WorkerScope { inner: RefCell::default(), }) } pub fn get_or_init_worker( &self, prefer: PreferWorkerKind, f: impl FnOnce(&mut dyn Worker) -> T, ) -> T { let mut inner = self.inner.borrow_mut(); let inner = inner.get_or_insert_with(move || match prefer { #[cfg(all( not(any(target_arch = "asmjs", target_arch = "wasm32")), feature = "rayon" ))] PreferWorkerKind::Multithreaded => WorkerScopeInner::Rayon(Default::default()), #[allow(unreachable_patterns)] #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] PreferWorkerKind::Multithreaded => WorkerScopeInner::Multithreaded(Default::default()), _ => WorkerScopeInner::Immediate(Default::default()), }); f(match &mut *inner { #[cfg(all( not(any(target_arch = "asmjs", target_arch = "wasm32")), feature = "rayon" ))] WorkerScopeInner::Rayon(worker) => worker, #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] WorkerScopeInner::Multithreaded(worker) => worker, WorkerScopeInner::Immediate(worker) => worker, }) } } pub fn compute_image_parallel( components: &[Component], data: Vec>, output_size: Dimensions, color_transform: ColorTransform, ) -> Result> { #[cfg(all( not(any(target_arch = "asmjs", target_arch = "wasm32")), feature = "rayon" ))] return rayon::compute_image_parallel(components, data, output_size, color_transform); #[allow(unreachable_code)] { let color_convert_func = choose_color_convert_func(components.len(), color_transform)?; let upsampler = Upsampler::new(components, output_size.width, output_size.height)?; let line_size = output_size.width as usize * components.len(); let mut image = vec![0u8; line_size * output_size.height as usize]; for (row, line) in image.chunks_mut(line_size).enumerate() { upsampler.upsample_and_interleave_row( &data, row, output_size.width as usize, line, color_convert_func, ); } Ok(image) } }