jpegxl_rs/parallel/
resizable_runner.rs

1/*
2This file is part of jpegxl-rs.
3
4jpegxl-rs is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 3 of the License, or
7(at your option) any later version.
8
9jpegxl-rs is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with jpegxl-rs.  If not, see <https://www.gnu.org/licenses/>.
16*/
17
18//! Wrapper for resizable thread pool implementation with C++ standard library
19
20use std::{ffi::c_void, ptr::null_mut};
21
22use jpegxl_sys::threads::resizable_parallel_runner as api;
23
24use super::{JxlParallelRunner, ParallelRunner};
25
26use crate::{decode::BasicInfo, memory::MemoryManager};
27
28/// Wrapper for resizable thread pool implementation with C++ standard library
29pub struct ResizableRunner<'mm> {
30    runner_ptr: *mut c_void,
31    _memory_manager: Option<&'mm dyn MemoryManager>,
32}
33
34impl<'mm> ResizableRunner<'mm> {
35    /// Construct with number of threads
36    #[must_use]
37    pub fn new(memory_manager: Option<&'mm dyn MemoryManager>) -> Option<Self> {
38        let mm = memory_manager.map(MemoryManager::manager);
39        let runner_ptr = unsafe {
40            api::JxlResizableParallelRunnerCreate(mm.as_ref().map_or(null_mut(), |mm| mm))
41        };
42
43        if runner_ptr.is_null() {
44            None
45        } else {
46            Some(Self {
47                runner_ptr,
48                _memory_manager: memory_manager,
49            })
50        }
51    }
52
53    /// Set number of threads depending on the size of the image
54    pub fn set_num_threads(&self, width: u64, height: u64) {
55        let num = unsafe { api::JxlResizableParallelRunnerSuggestThreads(width, height) };
56        unsafe { api::JxlResizableParallelRunnerSetThreads(self.runner_ptr, num as usize) };
57    }
58}
59
60impl Default for ResizableRunner<'_> {
61    fn default() -> Self {
62        Self {
63            runner_ptr: unsafe { api::JxlResizableParallelRunnerCreate(std::ptr::null()) },
64            _memory_manager: None,
65        }
66    }
67}
68
69impl ParallelRunner for ResizableRunner<'_> {
70    fn runner(&self) -> JxlParallelRunner {
71        api::JxlResizableParallelRunner
72    }
73
74    fn as_opaque_ptr(&self) -> *mut c_void {
75        self.runner_ptr
76    }
77
78    fn callback_basic_info(&self, info: &BasicInfo) {
79        self.set_num_threads(info.xsize.into(), info.ysize.into());
80    }
81}
82
83impl Drop for ResizableRunner<'_> {
84    fn drop(&mut self) {
85        unsafe { api::JxlResizableParallelRunnerDestroy(self.runner_ptr) };
86    }
87}
88
89#[cfg(test)]
90mod tests {
91
92    use crate::memory::tests::BumpManager;
93
94    use super::*;
95
96    #[test]
97    #[cfg_attr(coverage_nightly, coverage(off))]
98    fn test_construction() {
99        let memory_manager = BumpManager::new(1024);
100        let parallel_runner = ResizableRunner::new(Some(&memory_manager));
101        assert!(parallel_runner.is_some());
102    }
103}