1use crate::buffer::OidnBuffer;
4use crate::device::OidnDevice;
5use crate::sys;
6use crate::Error;
7use std::ffi::CString;
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub enum Quality {
12 #[default]
14 Default,
15 Fast,
17 Balanced,
19 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
34pub 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 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 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 pub fn set_hdr(&mut self, hdr: bool) -> &mut Self {
97 self.hdr = hdr;
98 self
99 }
100
101 pub fn set_srgb(&mut self, srgb: bool) -> &mut Self {
103 self.srgb = srgb;
104 self
105 }
106
107 pub fn set_clean_aux(&mut self, clean: bool) -> &mut Self {
109 self.clean_aux = clean;
110 self
111 }
112
113 pub fn set_input_scale(&mut self, scale: f32) -> &mut Self {
115 self.input_scale = scale;
116 self
117 }
118
119 pub fn set_quality(&mut self, quality: Quality) -> &mut Self {
121 self.quality = quality;
122 self
123 }
124
125 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 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 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 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 pub fn execute_in_place(&self, color: &mut [f32]) -> Result<(), Error> {
160 self.execute_with_aux(None, color, None, None)
161 }
162
163 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 pub fn execute(&self, color: Option<&[f32]>, output: &mut [f32]) -> Result<(), Error> {
175 self.execute_with_aux(color, output, None, None)
176 }
177
178 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 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 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
403pub 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 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 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 pub fn set_directional(&mut self, directional: bool) -> &mut Self {
454 self.directional = directional;
455 self
456 }
457
458 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 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 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 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 pub fn execute_in_place(&self, color: &mut [f32]) -> Result<(), Error> {
487 self.execute(None, color)
488 }
489
490 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
602pub use crate::sys::OIDNFormat;
608pub type ImageFormat = sys::OIDNFormat;
610
611pub 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn commit(&self) {
761 unsafe { sys::oidnCommitFilter(self.raw) };
762 }
763
764 pub fn execute(&self) {
766 unsafe { sys::oidnExecuteFilter(self.raw) };
767 }
768
769 pub fn execute_async(&self) {
771 unsafe { sys::oidnExecuteFilterAsync(self.raw) };
772 }
773
774 pub fn device(&self) -> &'a OidnDevice {
776 self.device
777 }
778
779 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<'_> {}