Skip to main content

mtl_gpu/device/
mod.rs

1//! Metal device interface.
2//!
3//! Corresponds to `Metal/MTLDevice.hpp`.
4//!
5//! The `Device` represents a GPU that can execute Metal commands. Use the
6//! [`system_default`] function to get the default GPU, or [`copy_all_devices`]
7//! (macOS only) to enumerate all available GPUs.
8//!
9//! # Example
10//!
11//! ```ignore
12//! use mtl_gpu::device;
13//!
14//! // Get the default GPU
15//! let device = device::system_default().expect("no Metal device");
16//! println!("Using GPU: {}", device.name());
17//! ```
18
19mod architecture;
20mod creation;
21mod features;
22mod limits;
23mod properties;
24
25// Resource creation modules
26mod acceleration;
27mod binary_archive;
28mod buffer;
29mod command_queue;
30mod depth_stencil;
31mod events;
32mod heap;
33mod indirect;
34mod io;
35mod library;
36mod mtl4;
37mod pipeline;
38mod residency_set;
39mod sampler;
40mod texture;
41
42// Re-export creation functions at module level
43pub use creation::{Timestamp, system_default};
44
45#[cfg(target_os = "macos")]
46pub use creation::{
47    DeviceObserver, copy_all_devices, copy_all_devices_with_observer, remove_device_observer,
48};
49
50// Re-export Architecture
51pub use architecture::Architecture;
52
53use std::ffi::c_void;
54use std::ptr::NonNull;
55
56use mtl_foundation::Referencing;
57
58/// A Metal device representing a GPU.
59///
60/// C++ equivalent: `MTL::Device`
61///
62/// The device is the central object in Metal. It is used to create all other
63/// Metal objects including command queues, buffers, textures, and pipelines.
64#[repr(transparent)]
65pub struct Device(pub(crate) NonNull<c_void>);
66
67impl Device {
68    /// Create a Device from a raw pointer.
69    ///
70    /// # Safety
71    ///
72    /// The pointer must be a valid Metal device object.
73    #[inline]
74    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
75        NonNull::new(ptr).map(Self)
76    }
77
78    /// Get the raw pointer to the device.
79    #[inline]
80    pub fn as_raw(&self) -> *mut c_void {
81        self.0.as_ptr()
82    }
83}
84
85impl Clone for Device {
86    fn clone(&self) -> Self {
87        // Retain the underlying object
88        unsafe {
89            mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
90        }
91        Self(self.0)
92    }
93}
94
95impl Drop for Device {
96    fn drop(&mut self) {
97        // Release the underlying object
98        unsafe {
99            mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
100        }
101    }
102}
103
104impl Referencing for Device {
105    #[inline]
106    fn as_ptr(&self) -> *const c_void {
107        self.0.as_ptr()
108    }
109}
110
111// SAFETY: Device is a reference-counted object that is thread-safe
112unsafe impl Send for Device {}
113unsafe impl Sync for Device {}
114
115impl std::fmt::Debug for Device {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.debug_struct("Device")
118            .field("name", &self.name())
119            .field("registry_id", &self.registry_id())
120            .finish()
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    #[test]
129    fn test_device_size() {
130        // Device should be pointer-sized
131        assert_eq!(
132            std::mem::size_of::<Device>(),
133            std::mem::size_of::<*mut c_void>()
134        );
135    }
136}