Skip to main content

oidn_wgpu/
filter.rs

1//! RT and RTLightmap denoising filters, plus generic filter API (full OIDN filter coverage).
2
3use crate::buffer::OidnBuffer;
4use crate::device::OidnDevice;
5use crate::sys;
6use crate::Error;
7use std::ffi::CString;
8
9/// Filter quality vs performance trade-off (OIDN 2.x).
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub enum Quality {
12    /// Default (high quality).
13    #[default]
14    Default,
15    /// Fast — for interactive/real-time preview.
16    Fast,
17    /// Balanced — interactive/real-time.
18    Balanced,
19    /// High — for final-frame rendering.
20    High,
21}
22
23impl Quality {
24    fn to_raw(self) -> sys::OIDNQuality {
25        match self {
26            Quality::Default => sys::OIDNQuality::Default,
27            Quality::Fast => sys::OIDNQuality::Fast,
28            Quality::Balanced => sys::OIDNQuality::Balanced,
29            Quality::High => sys::OIDNQuality::High,
30        }
31    }
32}
33
34/// Ray tracing denoising filter (OIDN "RT" filter).
35///
36/// Denoises a beauty (color) image, optionally using albedo and normal AOVs.
37/// Reuse the same filter for multiple frames when dimensions match.
38pub struct RtFilter<'a> {
39    device: &'a OidnDevice,
40    raw: sys::OIDNFilter,
41    width: u32,
42    height: u32,
43    hdr: bool,
44    srgb: bool,
45    clean_aux: bool,
46    input_scale: f32,
47    quality: Quality,
48}
49
50impl std::fmt::Debug for RtFilter<'_> {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        f.debug_struct("RtFilter")
53            .field("width", &self.width)
54            .field("height", &self.height)
55            .field("hdr", &self.hdr)
56            .field("srgb", &self.srgb)
57            .field("quality", &self.quality)
58            .finish_non_exhaustive()
59    }
60}
61
62impl<'a> RtFilter<'a> {
63    /// Creates a new RT filter. Reuse the same filter for multiple frames when dimensions match.
64    ///
65    /// # Errors
66    ///
67    /// Returns [`Error::FilterCreationFailed`] if the RT filter type is not available, or the
68    /// device's last error (e.g. [`Error::OidnError`]).
69    pub fn new(device: &'a OidnDevice) -> Result<Self, Error> {
70        let type_name = CString::new("RT").unwrap();
71        let raw = unsafe { sys::oidnNewFilter(device.raw(), type_name.as_ptr()) };
72        if raw.is_null() {
73            return Err(device.take_error().unwrap_or(Error::FilterCreationFailed));
74        }
75        Ok(Self {
76            device,
77            raw,
78            width: 0,
79            height: 0,
80            hdr: true,
81            srgb: false,
82            clean_aux: false,
83            input_scale: f32::NAN,
84            quality: Quality::Default,
85        })
86    }
87
88    /// Image dimensions (must be set before execute).
89    pub fn set_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
90        self.width = width;
91        self.height = height;
92        self
93    }
94
95    /// Whether the input is HDR. Default: true.
96    pub fn set_hdr(&mut self, hdr: bool) -> &mut Self {
97        self.hdr = hdr;
98        self
99    }
100
101    /// Whether the input is sRGB (LDR). Default: false.
102    pub fn set_srgb(&mut self, srgb: bool) -> &mut Self {
103        self.srgb = srgb;
104        self
105    }
106
107    /// Whether albedo/normal are noise-free (prefiltered). Default: false.
108    pub fn set_clean_aux(&mut self, clean: bool) -> &mut Self {
109        self.clean_aux = clean;
110        self
111    }
112
113    /// Input scale (e.g. for HDR). NaN = auto.
114    pub fn set_input_scale(&mut self, scale: f32) -> &mut Self {
115        self.input_scale = scale;
116        self
117    }
118
119    /// Filter quality. Default: High.
120    pub fn set_quality(&mut self, quality: Quality) -> &mut Self {
121        self.quality = quality;
122        self
123    }
124
125    /// Gets a boolean filter parameter (e.g. `"hdr"`, `"srgb"`).
126    pub fn get_bool(&self, name: &str) -> bool {
127        let c_name = CString::new(name).unwrap();
128        unsafe { sys::oidnGetFilterBool(self.raw, c_name.as_ptr()) }
129    }
130
131    /// Gets an integer filter parameter (e.g. `"quality"`).
132    pub fn get_int(&self, name: &str) -> i32 {
133        let c_name = CString::new(name).unwrap();
134        unsafe { sys::oidnGetFilterInt(self.raw, c_name.as_ptr()) }
135    }
136
137    /// Gets a float filter parameter (e.g. `"inputScale"`).
138    pub fn get_float(&self, name: &str) -> f32 {
139        let c_name = CString::new(name).unwrap();
140        unsafe { sys::oidnGetFilterFloat(self.raw, c_name.as_ptr()) }
141    }
142
143    /// Sets the progress monitor callback. Callback receives progress in [0,1]; return `false` to cancel.
144    /// Safe to call with `(None, null)` to clear. Callback must not panic.
145    pub unsafe fn set_progress_monitor_raw(
146        &self,
147        func: sys::OIDNProgressMonitorFunction,
148        user_ptr: *mut std::ffi::c_void,
149    ) {
150        sys::oidnSetFilterProgressMonitorFunction(self.raw, func, user_ptr);
151    }
152
153    /// Denoises color in-place. `color` must be `width * height * 3` floats (RGB).
154    ///
155    /// # Errors
156    ///
157    /// Returns [`Error::InvalidDimensions`] if dimensions are unset or buffer sizes do not match,
158    /// or an OIDN error from the device.
159    pub fn execute_in_place(&self, color: &mut [f32]) -> Result<(), Error> {
160        self.execute_with_aux(None, color, None, None)
161    }
162
163    /// Denoises color in-place with optional albedo and normal AOVs (each `width * height * 3` floats).
164    pub fn execute_in_place_with_aux(
165        &self,
166        color: &mut [f32],
167        albedo: Option<&[f32]>,
168        normal: Option<&[f32]>,
169    ) -> Result<(), Error> {
170        self.execute_with_aux(None, color, albedo, normal)
171    }
172
173    /// Denoises color into output. Slices must be `width * height * 3` floats (RGB).
174    pub fn execute(&self, color: Option<&[f32]>, output: &mut [f32]) -> Result<(), Error> {
175        self.execute_with_aux(color, output, None, None)
176    }
177
178    /// Denoises color into output with optional albedo and normal AOVs (each `width * height * 3` floats).
179    pub fn execute_with_aux(
180        &self,
181        color: Option<&[f32]>,
182        output: &mut [f32],
183        albedo: Option<&[f32]>,
184        normal: Option<&[f32]>,
185    ) -> Result<(), Error> {
186        let w = self.width as usize;
187        let h = self.height as usize;
188        if w == 0 || h == 0 {
189            return Err(Error::InvalidDimensions);
190        }
191        let n = w * h * 3;
192        if output.len() != n {
193            return Err(Error::InvalidDimensions);
194        }
195        if let Some(c) = color {
196            if c.len() != n {
197                return Err(Error::InvalidDimensions);
198            }
199        }
200
201        let device = self.device.raw();
202        let color_buf = if let Some(c) = color {
203            let buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
204            if buf.is_null() {
205                return Err(self.device.take_error().unwrap_or(Error::OutOfMemory));
206            }
207            unsafe {
208                sys::oidnWriteBuffer(buf, 0, n * std::mem::size_of::<f32>(), c.as_ptr() as *const _);
209            }
210            Some(buf)
211        } else {
212            None
213        };
214        let out_buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
215        if out_buf.is_null() {
216            if let Some(b) = color_buf {
217                unsafe { sys::oidnReleaseBuffer(b) };
218            }
219            return Err(self.device.take_error().unwrap_or(Error::OutOfMemory));
220        }
221        if color.is_none() {
222            unsafe {
223                sys::oidnWriteBuffer(
224                    out_buf,
225                    0,
226                    n * std::mem::size_of::<f32>(),
227                    output.as_ptr() as *const _,
228                );
229            }
230        }
231
232        // Validate and create optional albedo/normal buffers
233        if let Some(a) = albedo {
234            if a.len() != n {
235                if let Some(b) = color_buf {
236                    unsafe { sys::oidnReleaseBuffer(b) };
237                }
238                unsafe { sys::oidnReleaseBuffer(out_buf) };
239                return Err(Error::InvalidDimensions);
240            }
241        }
242        if let Some(norm) = normal {
243            if norm.len() != n {
244                if let Some(b) = color_buf {
245                    unsafe { sys::oidnReleaseBuffer(b) };
246                }
247                unsafe { sys::oidnReleaseBuffer(out_buf) };
248                return Err(Error::InvalidDimensions);
249            }
250        }
251
252        let albedo_buf = albedo.map(|a| {
253            let buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
254            if !buf.is_null() {
255                unsafe {
256                    sys::oidnWriteBuffer(buf, 0, n * std::mem::size_of::<f32>(), a.as_ptr() as *const _);
257                }
258            }
259            buf
260        });
261        let normal_buf = normal.map(|norm| {
262            let buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
263            if !buf.is_null() {
264                unsafe {
265                    sys::oidnWriteBuffer(buf, 0, n * std::mem::size_of::<f32>(), norm.as_ptr() as *const _);
266                }
267            }
268            buf
269        });
270
271        if albedo_buf.is_some_and(|p| p.is_null())
272            || normal_buf.is_some_and(|p| p.is_null())
273        {
274            if let Some(b) = color_buf {
275                unsafe { sys::oidnReleaseBuffer(b) };
276            }
277            unsafe { sys::oidnReleaseBuffer(out_buf) };
278            for b in albedo_buf.into_iter().chain(normal_buf) {
279                if !b.is_null() {
280                    unsafe { sys::oidnReleaseBuffer(b) };
281                }
282            }
283            return Err(self.device.take_error().unwrap_or(Error::OutOfMemory));
284        }
285
286        let color_ptr = color_buf.unwrap_or(out_buf);
287        unsafe {
288            let c_color = CString::new("color").unwrap();
289            let c_output = CString::new("output").unwrap();
290            let c_albedo = CString::new("albedo").unwrap();
291            let c_normal = CString::new("normal").unwrap();
292            let c_hdr = CString::new("hdr").unwrap();
293            let c_srgb = CString::new("srgb").unwrap();
294            let c_clean_aux = CString::new("cleanAux").unwrap();
295            let c_input_scale = CString::new("inputScale").unwrap();
296            let c_quality = CString::new("quality").unwrap();
297
298            sys::oidnSetFilterImage(
299                self.raw,
300                c_color.as_ptr(),
301                color_ptr,
302                sys::OIDNFormat::Float3,
303                w,
304                h,
305                0,
306                0,
307                0,
308            );
309            sys::oidnSetFilterImage(
310                self.raw,
311                c_output.as_ptr(),
312                out_buf,
313                sys::OIDNFormat::Float3,
314                w,
315                h,
316                0,
317                0,
318                0,
319            );
320            if let Some(ab) = albedo_buf {
321                if !ab.is_null() {
322                    sys::oidnSetFilterImage(
323                        self.raw,
324                        c_albedo.as_ptr(),
325                        ab,
326                        sys::OIDNFormat::Float3,
327                        w,
328                        h,
329                        0,
330                        0,
331                        0,
332                    );
333                }
334            }
335            if let Some(nb) = normal_buf {
336                if !nb.is_null() {
337                    sys::oidnSetFilterImage(
338                        self.raw,
339                        c_normal.as_ptr(),
340                        nb,
341                        sys::OIDNFormat::Float3,
342                        w,
343                        h,
344                        0,
345                        0,
346                        0,
347                    );
348                }
349            }
350            sys::oidnSetFilterBool(self.raw, c_hdr.as_ptr(), self.hdr);
351            sys::oidnSetFilterBool(self.raw, c_srgb.as_ptr(), self.srgb);
352            sys::oidnSetFilterBool(self.raw, c_clean_aux.as_ptr(), self.clean_aux);
353            sys::oidnSetFilterFloat(self.raw, c_input_scale.as_ptr(), self.input_scale);
354            sys::oidnSetFilterInt(self.raw, c_quality.as_ptr(), self.quality.to_raw() as i32);
355
356            sys::oidnCommitFilter(self.raw);
357            sys::oidnExecuteFilter(self.raw);
358        }
359
360        // Required for GPU (e.g. CUDA) where execute is async; ensures result is ready before readback.
361        self.device.sync();
362
363        if let Some(b) = albedo_buf {
364            if !b.is_null() {
365                unsafe { sys::oidnReleaseBuffer(b) };
366            }
367        }
368        if let Some(b) = normal_buf {
369            if !b.is_null() {
370                unsafe { sys::oidnReleaseBuffer(b) };
371            }
372        }
373
374        unsafe {
375            sys::oidnReadBuffer(
376                out_buf,
377                0,
378                n * std::mem::size_of::<f32>(),
379                output.as_mut_ptr() as *mut _,
380            );
381        }
382
383        if let Some(b) = color_buf {
384            unsafe { sys::oidnReleaseBuffer(b) };
385        }
386        unsafe { sys::oidnReleaseBuffer(out_buf) };
387
388        if let Some(e) = self.device.take_error() {
389            return Err(e);
390        }
391        Ok(())
392    }
393}
394
395impl Drop for RtFilter<'_> {
396    fn drop(&mut self) {
397        unsafe { sys::oidnReleaseFilter(self.raw) }
398    }
399}
400
401unsafe impl Send for RtFilter<'_> {}
402
403// ---------------------------------------------------------------------------
404// RTLightmap filter (lightmap denoising; requires OIDN built with RTLightmap)
405// ---------------------------------------------------------------------------
406
407/// Ray-traced lightmap denoising filter (OIDN "RTLightmap").
408///
409/// Use for denoising baked lightmaps. Requires OIDN built with `OIDN_FILTER_RTLIGHTMAP`.
410pub struct RtLightmapFilter<'a> {
411    device: &'a OidnDevice,
412    raw: sys::OIDNFilter,
413    width: u32,
414    height: u32,
415    directional: bool,
416}
417
418impl std::fmt::Debug for RtLightmapFilter<'_> {
419    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420        f.debug_struct("RtLightmapFilter")
421            .field("width", &self.width)
422            .field("height", &self.height)
423            .field("directional", &self.directional)
424            .finish_non_exhaustive()
425    }
426}
427
428impl<'a> RtLightmapFilter<'a> {
429    /// Creates a new RTLightmap filter. Returns an error if OIDN was not built with RTLightmap support.
430    pub fn new(device: &'a OidnDevice) -> Result<Self, Error> {
431        let type_name = CString::new("RTLightmap").unwrap();
432        let raw = unsafe { sys::oidnNewFilter(device.raw(), type_name.as_ptr()) };
433        if raw.is_null() {
434            return Err(device.take_error().unwrap_or(Error::FilterCreationFailed));
435        }
436        Ok(Self {
437            device,
438            raw,
439            width: 0,
440            height: 0,
441            directional: false,
442        })
443    }
444
445    /// Image dimensions (must be set before execute).
446    pub fn set_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
447        self.width = width;
448        self.height = height;
449        self
450    }
451
452    /// If true, use directional lightmap model; if false, HDR. Default: false.
453    pub fn set_directional(&mut self, directional: bool) -> &mut Self {
454        self.directional = directional;
455        self
456    }
457
458    /// Gets a boolean filter parameter (e.g. `"directional"`).
459    pub fn get_bool(&self, name: &str) -> bool {
460        let c_name = CString::new(name).unwrap();
461        unsafe { sys::oidnGetFilterBool(self.raw, c_name.as_ptr()) }
462    }
463
464    /// Gets an integer filter parameter.
465    pub fn get_int(&self, name: &str) -> i32 {
466        let c_name = CString::new(name).unwrap();
467        unsafe { sys::oidnGetFilterInt(self.raw, c_name.as_ptr()) }
468    }
469
470    /// Gets a float filter parameter.
471    pub fn get_float(&self, name: &str) -> f32 {
472        let c_name = CString::new(name).unwrap();
473        unsafe { sys::oidnGetFilterFloat(self.raw, c_name.as_ptr()) }
474    }
475
476    /// Sets the progress monitor callback. Call with `(None, null)` to clear.
477    pub unsafe fn set_progress_monitor_raw(
478        &self,
479        func: sys::OIDNProgressMonitorFunction,
480        user_ptr: *mut std::ffi::c_void,
481    ) {
482        sys::oidnSetFilterProgressMonitorFunction(self.raw, func, user_ptr);
483    }
484
485    /// Denoises lightmap in-place. `color` must be `width * height * 3` floats (RGB).
486    pub fn execute_in_place(&self, color: &mut [f32]) -> Result<(), Error> {
487        self.execute(None, color)
488    }
489
490    /// Denoises lightmap: reads from `color` (if provided) or uses `output` as input, writes to `output`.
491    /// All buffers must be `width * height * 3` floats (RGB).
492    pub fn execute(
493        &self,
494        color: Option<&[f32]>,
495        output: &mut [f32],
496    ) -> Result<(), Error> {
497        let w = self.width as usize;
498        let h = self.height as usize;
499        if w == 0 || h == 0 {
500            return Err(Error::InvalidDimensions);
501        }
502        let n = w * h * 3;
503        if output.len() != n {
504            return Err(Error::InvalidDimensions);
505        }
506        if let Some(c) = color {
507            if c.len() != n {
508                return Err(Error::InvalidDimensions);
509            }
510        }
511
512        let device = self.device.raw();
513        let color_buf = if let Some(c) = color {
514            let buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
515            if buf.is_null() {
516                return Err(self.device.take_error().unwrap_or(Error::OutOfMemory));
517            }
518            unsafe {
519                sys::oidnWriteBuffer(buf, 0, n * std::mem::size_of::<f32>(), c.as_ptr() as *const _);
520            }
521            Some(buf)
522        } else {
523            None
524        };
525        let out_buf = unsafe { sys::oidnNewBuffer(device, n * std::mem::size_of::<f32>()) };
526        if out_buf.is_null() {
527            if let Some(b) = color_buf {
528                unsafe { sys::oidnReleaseBuffer(b) };
529            }
530            return Err(self.device.take_error().unwrap_or(Error::OutOfMemory));
531        }
532        if color.is_none() {
533            unsafe {
534                sys::oidnWriteBuffer(
535                    out_buf,
536                    0,
537                    n * std::mem::size_of::<f32>(),
538                    output.as_ptr() as *const _,
539                );
540            }
541        }
542
543        let color_ptr = color_buf.unwrap_or(out_buf);
544        unsafe {
545            let c_color = CString::new("color").unwrap();
546            let c_output = CString::new("output").unwrap();
547            let c_directional = CString::new("directional").unwrap();
548            sys::oidnSetFilterImage(
549                self.raw,
550                c_color.as_ptr(),
551                color_ptr,
552                sys::OIDNFormat::Float3,
553                w,
554                h,
555                0,
556                0,
557                0,
558            );
559            sys::oidnSetFilterImage(
560                self.raw,
561                c_output.as_ptr(),
562                out_buf,
563                sys::OIDNFormat::Float3,
564                w,
565                h,
566                0,
567                0,
568                0,
569            );
570            sys::oidnSetFilterInt(self.raw, c_directional.as_ptr(), self.directional as i32);
571            sys::oidnCommitFilter(self.raw);
572            sys::oidnExecuteFilter(self.raw);
573        }
574        self.device.sync();
575        unsafe {
576            sys::oidnReadBuffer(
577                out_buf,
578                0,
579                n * std::mem::size_of::<f32>(),
580                output.as_mut_ptr() as *mut _,
581            );
582        }
583        if let Some(b) = color_buf {
584            unsafe { sys::oidnReleaseBuffer(b) };
585        }
586        unsafe { sys::oidnReleaseBuffer(out_buf) };
587        if let Some(e) = self.device.take_error() {
588            return Err(e);
589        }
590        Ok(())
591    }
592}
593
594impl Drop for RtLightmapFilter<'_> {
595    fn drop(&mut self) {
596        unsafe { sys::oidnReleaseFilter(self.raw) }
597    }
598}
599
600unsafe impl Send for RtLightmapFilter<'_> {}
601
602// ---------------------------------------------------------------------------
603// Generic filter (full OIDN filter API: any type, shared images/data, async)
604// ---------------------------------------------------------------------------
605
606/// Image format for filter image parameters. Re-exported so variants (e.g. `OIDNFormat::Float3`) are constructible.
607pub use crate::sys::OIDNFormat;
608/// Type alias for filter image format (same as `OIDNFormat`).
609pub type ImageFormat = sys::OIDNFormat;
610
611/// Generic filter created by type name (e.g. `"RT"`, `"RTLightmap"`).
612///
613/// Exposes the full OIDN filter API: buffer or shared image/data, progress monitor, async execute.
614pub struct Filter<'a> {
615    device: &'a OidnDevice,
616    raw: sys::OIDNFilter,
617}
618
619impl std::fmt::Debug for Filter<'_> {
620    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
621        f.debug_struct("Filter").finish_non_exhaustive()
622    }
623}
624
625impl<'a> Filter<'a> {
626    /// Creates a filter of the given type (e.g. `"RT"`, `"RTLightmap"`).
627    pub fn new(device: &'a OidnDevice, type_name: &str) -> Result<Self, Error> {
628        let c_name = CString::new(type_name).map_err(|_| Error::FilterCreationFailed)?;
629        let raw = unsafe { sys::oidnNewFilter(device.raw(), c_name.as_ptr()) };
630        if raw.is_null() {
631            return Err(device.take_error().unwrap_or(Error::FilterCreationFailed));
632        }
633        Ok(Self { device, raw })
634    }
635
636    /// Sets an image parameter from an OIDN buffer.
637    pub fn set_image(
638        &self,
639        name: &str,
640        buffer: &OidnBuffer,
641        format: ImageFormat,
642        width: usize,
643        height: usize,
644        byte_offset: usize,
645        pixel_byte_stride: usize,
646        row_byte_stride: usize,
647    ) {
648        let c_name = CString::new(name).unwrap();
649        unsafe {
650            sys::oidnSetFilterImage(
651                self.raw,
652                c_name.as_ptr(),
653                buffer.raw(),
654                format,
655                width,
656                height,
657                byte_offset,
658                pixel_byte_stride,
659                row_byte_stride,
660            );
661        }
662    }
663
664    /// Sets an image parameter from a raw device pointer (zero-copy). Caller keeps ownership.
665    pub unsafe fn set_shared_image(
666        &self,
667        name: &str,
668        dev_ptr: *mut std::ffi::c_void,
669        format: ImageFormat,
670        width: usize,
671        height: usize,
672        byte_offset: usize,
673        pixel_byte_stride: usize,
674        row_byte_stride: usize,
675    ) {
676        let c_name = CString::new(name).unwrap();
677        sys::oidnSetSharedFilterImage(
678            self.raw,
679            c_name.as_ptr(),
680            dev_ptr,
681            format,
682            width,
683            height,
684            byte_offset,
685            pixel_byte_stride,
686            row_byte_stride,
687        );
688    }
689
690    /// Unsets a previously set image parameter.
691    pub fn unset_image(&self, name: &str) {
692        let c_name = CString::new(name).unwrap();
693        unsafe { sys::oidnUnsetFilterImage(self.raw, c_name.as_ptr()) };
694    }
695
696    /// Sets an opaque data parameter (host pointer). Caller keeps ownership.
697    pub unsafe fn set_shared_data(&self, name: &str, host_ptr: *mut std::ffi::c_void, byte_size: usize) {
698        let c_name = CString::new(name).unwrap();
699        sys::oidnSetSharedFilterData(self.raw, c_name.as_ptr(), host_ptr, byte_size);
700    }
701
702    /// Notifies the filter that the contents of an opaque data parameter have changed.
703    pub fn update_data(&self, name: &str) {
704        let c_name = CString::new(name).unwrap();
705        unsafe { sys::oidnUpdateFilterData(self.raw, c_name.as_ptr()) };
706    }
707
708    /// Unsets a previously set opaque data parameter.
709    pub fn unset_data(&self, name: &str) {
710        let c_name = CString::new(name).unwrap();
711        unsafe { sys::oidnUnsetFilterData(self.raw, c_name.as_ptr()) };
712    }
713
714    /// Sets a boolean parameter.
715    pub fn set_bool(&self, name: &str, value: bool) {
716        let c_name = CString::new(name).unwrap();
717        unsafe { sys::oidnSetFilterBool(self.raw, c_name.as_ptr(), value) };
718    }
719
720    /// Gets a boolean parameter.
721    pub fn get_bool(&self, name: &str) -> bool {
722        let c_name = CString::new(name).unwrap();
723        unsafe { sys::oidnGetFilterBool(self.raw, c_name.as_ptr()) }
724    }
725
726    /// Sets an integer parameter.
727    pub fn set_int(&self, name: &str, value: i32) {
728        let c_name = CString::new(name).unwrap();
729        unsafe { sys::oidnSetFilterInt(self.raw, c_name.as_ptr(), value) };
730    }
731
732    /// Gets an integer parameter.
733    pub fn get_int(&self, name: &str) -> i32 {
734        let c_name = CString::new(name).unwrap();
735        unsafe { sys::oidnGetFilterInt(self.raw, c_name.as_ptr()) }
736    }
737
738    /// Sets a float parameter.
739    pub fn set_float(&self, name: &str, value: f32) {
740        let c_name = CString::new(name).unwrap();
741        unsafe { sys::oidnSetFilterFloat(self.raw, c_name.as_ptr(), value) };
742    }
743
744    /// Gets a float parameter.
745    pub fn get_float(&self, name: &str) -> f32 {
746        let c_name = CString::new(name).unwrap();
747        unsafe { sys::oidnGetFilterFloat(self.raw, c_name.as_ptr()) }
748    }
749
750    /// Sets the progress monitor callback. Call with `(None, null)` to clear.
751    pub unsafe fn set_progress_monitor_raw(
752        &self,
753        func: sys::OIDNProgressMonitorFunction,
754        user_ptr: *mut std::ffi::c_void,
755    ) {
756        sys::oidnSetFilterProgressMonitorFunction(self.raw, func, user_ptr);
757    }
758
759    /// Commits all previous filter parameter changes. Must be called before execute.
760    pub fn commit(&self) {
761        unsafe { sys::oidnCommitFilter(self.raw) };
762    }
763
764    /// Executes the filter (synchronous). Call `device.sync()` after if using a GPU device.
765    pub fn execute(&self) {
766        unsafe { sys::oidnExecuteFilter(self.raw) };
767    }
768
769    /// Executes the filter asynchronously. Call `device.sync()` before reading output.
770    pub fn execute_async(&self) {
771        unsafe { sys::oidnExecuteFilterAsync(self.raw) };
772    }
773
774    /// Underlying device (for sync/error).
775    pub fn device(&self) -> &'a OidnDevice {
776        self.device
777    }
778
779    /// Retains the filter (increments OIDN reference count). For advanced interop when sharing the filter.
780    pub fn retain(&self) {
781        unsafe { sys::oidnRetainFilter(self.raw) };
782    }
783}
784
785impl Drop for Filter<'_> {
786    fn drop(&mut self) {
787        unsafe { sys::oidnReleaseFilter(self.raw) }
788    }
789}
790
791unsafe impl Send for Filter<'_> {}