Skip to main content

oidn_wgpu/
buffer.rs

1//! OIDN buffer (host/device memory, shared/imported). Full buffer API.
2//!
3//! See [`OidnBuffer`] for construction and [`BufferStorage`] for storage modes.
4
5use crate::device::OidnDevice;
6use crate::error::Error;
7use crate::sys;
8
9/// Buffer storage mode.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11#[repr(u32)]
12pub enum BufferStorage {
13    Undefined = 0,
14    /// Host-accessible, device can access.
15    Host = 1,
16    /// Device-only, host cannot access.
17    Device = 2,
18    /// Managed (migrated between host and device). Check device param `managedMemorySupported`.
19    Managed = 3,
20}
21
22impl From<sys::OIDNStorage> for BufferStorage {
23    fn from(s: sys::OIDNStorage) -> Self {
24        match s {
25            sys::OIDNStorage::Undefined => BufferStorage::Undefined,
26            sys::OIDNStorage::Host => BufferStorage::Host,
27            sys::OIDNStorage::Device => BufferStorage::Device,
28            sys::OIDNStorage::Managed => BufferStorage::Managed,
29        }
30    }
31}
32
33impl From<BufferStorage> for sys::OIDNStorage {
34    fn from(s: BufferStorage) -> sys::OIDNStorage {
35        match s {
36            BufferStorage::Undefined => sys::OIDNStorage::Undefined,
37            BufferStorage::Host => sys::OIDNStorage::Host,
38            BufferStorage::Device => sys::OIDNStorage::Device,
39            BufferStorage::Managed => sys::OIDNStorage::Managed,
40        }
41    }
42}
43
44/// External memory type for importing buffers (FD, Win32, etc.).
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46#[repr(u32)]
47pub enum ExternalMemoryTypeFlag {
48    None = 0,
49    OpaqueFD = 1 << 0,
50    DmaBuf = 1 << 1,
51    OpaqueWin32 = 1 << 2,
52    OpaqueWin32KMT = 1 << 3,
53    D3D11Texture = 1 << 4,
54    D3D11TextureKMT = 1 << 5,
55    D3D11Resource = 1 << 6,
56    D3D11ResourceKMT = 1 << 7,
57    D3D12Heap = 1 << 8,
58    D3D12Resource = 1 << 9,
59}
60
61impl From<ExternalMemoryTypeFlag> for sys::OIDNExternalMemoryTypeFlag {
62    fn from(f: ExternalMemoryTypeFlag) -> sys::OIDNExternalMemoryTypeFlag {
63        unsafe { std::mem::transmute(f as u32) }
64    }
65}
66
67/// OIDN buffer. Owns or wraps device-accessible memory.
68pub struct OidnBuffer {
69    pub(crate) raw: sys::OIDNBuffer,
70    _device: std::marker::PhantomData<OidnDevice>,
71}
72
73impl std::fmt::Debug for OidnBuffer {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        f.debug_struct("OidnBuffer")
76            .field("size", &self.size())
77            .field("storage", &self.storage())
78            .finish_non_exhaustive()
79    }
80}
81
82impl OidnBuffer {
83    /// Creates a buffer (host and device accessible) of the given size in bytes.
84    ///
85    /// # Errors
86    ///
87    /// Returns [`Error::OutOfMemory`] if allocation fails, or an OIDN error from the device.
88    pub fn new(device: &OidnDevice, byte_size: usize) -> Result<Self, Error> {
89        let raw = unsafe { sys::oidnNewBuffer(device.raw(), byte_size) };
90        if raw.is_null() {
91            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
92        }
93        Ok(Self {
94            raw,
95            _device: std::marker::PhantomData,
96        })
97    }
98
99    /// Creates a buffer with the specified storage mode.
100    ///
101    /// # Errors
102    ///
103    /// Returns [`Error::OutOfMemory`] if allocation fails, or an OIDN error from the device.
104    pub fn new_with_storage(
105        device: &OidnDevice,
106        byte_size: usize,
107        storage: BufferStorage,
108    ) -> Result<Self, Error> {
109        let raw = unsafe {
110            sys::oidnNewBufferWithStorage(device.raw(), byte_size, storage.into())
111        };
112        if raw.is_null() {
113            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
114        }
115        Ok(Self {
116            raw,
117            _device: std::marker::PhantomData,
118        })
119    }
120
121    /// Creates a shared buffer from user-owned device memory. OIDN does not take ownership.
122    ///
123    /// # Safety
124    ///
125    /// `dev_ptr` must point to valid device memory of at least `byte_size` bytes, and remain
126    /// valid for the lifetime of OIDN operations using this buffer.
127    ///
128    /// # Errors
129    ///
130    /// Returns [`Error::OutOfMemory`] or an OIDN error if creation fails.
131    pub unsafe fn new_shared(device: &OidnDevice, dev_ptr: *mut std::ffi::c_void, byte_size: usize) -> Result<Self, Error> {
132        let raw = sys::oidnNewSharedBuffer(device.raw(), dev_ptr, byte_size);
133        if raw.is_null() {
134            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
135        }
136        Ok(Self {
137            raw,
138            _device: std::marker::PhantomData,
139        })
140    }
141
142    /// Creates a shared buffer from a POSIX file descriptor (e.g. DMA-BUF).
143    ///
144    /// # Errors
145    ///
146    /// Returns [`Error::OutOfMemory`] or an OIDN error if creation fails.
147    pub fn new_shared_from_fd(
148        device: &OidnDevice,
149        fd_type: ExternalMemoryTypeFlag,
150        fd: i32,
151        byte_size: usize,
152    ) -> Result<Self, Error> {
153        let raw = unsafe {
154            sys::oidnNewSharedBufferFromFD(device.raw(), fd_type.into(), fd, byte_size)
155        };
156        if raw.is_null() {
157            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
158        }
159        Ok(Self {
160            raw,
161            _device: std::marker::PhantomData,
162        })
163    }
164
165    /// Creates a shared buffer from a Win32 handle.
166    ///
167    /// # Safety
168    ///
169    /// `handle` and `name` must be valid for the given `handle_type` and remain valid for the
170    /// lifetime of OIDN operations using this buffer.
171    ///
172    /// # Errors
173    ///
174    /// Returns [`Error::OutOfMemory`] or an OIDN error if creation fails.
175    pub unsafe fn new_shared_from_win32_handle(
176        device: &OidnDevice,
177        handle_type: ExternalMemoryTypeFlag,
178        handle: *mut std::ffi::c_void,
179        name: *const std::ffi::c_void,
180        byte_size: usize,
181    ) -> Result<Self, Error> {
182        let raw = sys::oidnNewSharedBufferFromWin32Handle(
183            device.raw(),
184            handle_type.into(),
185            handle,
186            name,
187            byte_size,
188        );
189        if raw.is_null() {
190            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
191        }
192        Ok(Self {
193            raw,
194            _device: std::marker::PhantomData,
195        })
196    }
197
198    /// Creates a shared buffer from a Metal buffer (MTLBuffer). Only shared/private with hazard tracking.
199    ///
200    /// # Safety
201    ///
202    /// `metal_buffer` must be a valid MTLBuffer and remain valid for the lifetime of OIDN operations.
203    ///
204    /// # Errors
205    ///
206    /// Returns [`Error::OutOfMemory`] or an OIDN error if creation fails.
207    pub unsafe fn new_shared_from_metal(
208        device: &OidnDevice,
209        metal_buffer: *mut std::ffi::c_void,
210    ) -> Result<Self, Error> {
211        let raw = sys::oidnNewSharedBufferFromMetal(device.raw(), metal_buffer);
212        if raw.is_null() {
213            return Err(device.take_error().unwrap_or(Error::OutOfMemory));
214        }
215        Ok(Self {
216            raw,
217            _device: std::marker::PhantomData,
218        })
219    }
220
221    /// Size in bytes.
222    pub fn size(&self) -> usize {
223        unsafe { sys::oidnGetBufferSize(self.raw) }
224    }
225
226    /// Storage mode.
227    pub fn storage(&self) -> BufferStorage {
228        unsafe { sys::oidnGetBufferStorage(self.raw) }.into()
229    }
230
231    /// Raw pointer to buffer data (device-accessible; may be null for device-only storage).
232    pub fn data(&self) -> *mut std::ffi::c_void {
233        unsafe { sys::oidnGetBufferData(self.raw) }
234    }
235
236    /// Copies from buffer to host memory (synchronous).
237    ///
238    /// # Safety
239    /// `dst` must point to at least `byte_size` bytes of valid, writable memory.
240    pub unsafe fn read(&self, byte_offset: usize, byte_size: usize, dst: *mut std::ffi::c_void) {
241        sys::oidnReadBuffer(self.raw, byte_offset, byte_size, dst);
242    }
243
244    /// Copies from buffer to host memory (asynchronous). Call `device.sync()` before using `dst`.
245    ///
246    /// # Safety
247    /// `dst` must point to at least `byte_size` bytes of valid, writable memory.
248    pub unsafe fn read_async(&self, byte_offset: usize, byte_size: usize, dst: *mut std::ffi::c_void) {
249        sys::oidnReadBufferAsync(self.raw, byte_offset, byte_size, dst);
250    }
251
252    /// Copies from host memory to buffer (synchronous).
253    ///
254    /// # Safety
255    /// `src` must point to at least `byte_size` bytes of valid, readable memory.
256    pub unsafe fn write(&self, byte_offset: usize, byte_size: usize, src: *const std::ffi::c_void) {
257        sys::oidnWriteBuffer(self.raw, byte_offset, byte_size, src);
258    }
259
260    /// Copies from host memory to buffer (asynchronous). Call `device.sync()` before using buffer in a filter.
261    ///
262    /// # Safety
263    /// `src` must point to at least `byte_size` bytes of valid, readable memory.
264    pub unsafe fn write_async(&self, byte_offset: usize, byte_size: usize, src: *const std::ffi::c_void) {
265        sys::oidnWriteBufferAsync(self.raw, byte_offset, byte_size, src);
266    }
267
268    /// Retains the buffer (increments OIDN reference count). For advanced interop when sharing the buffer.
269    pub fn retain(&self) {
270        unsafe { sys::oidnRetainBuffer(self.raw) };
271    }
272
273    pub(crate) fn raw(&self) -> sys::OIDNBuffer {
274        self.raw
275    }
276}
277
278impl Drop for OidnBuffer {
279    fn drop(&mut self) {
280        unsafe { sys::oidnReleaseBuffer(self.raw) }
281    }
282}
283
284unsafe impl Send for OidnBuffer {}
285unsafe impl Sync for OidnBuffer {}