Skip to main content

mtl_gpu/device/
sampler.rs

1//! Device sampler state creation methods.
2//!
3//! Corresponds to sampler state creation methods in `Metal/MTLDevice.hpp`.
4
5use std::ffi::c_void;
6
7use mtl_foundation::Referencing;
8use mtl_sys::{msg_send_1, sel};
9
10use super::Device;
11use crate::error::ValidationError;
12use crate::sampler::{SamplerDescriptor, SamplerState};
13
14impl Device {
15    // =========================================================================
16    // Sampler State Creation
17    // =========================================================================
18
19    /// Create a new sampler state with the specified descriptor.
20    ///
21    /// C++ equivalent: `SamplerState* newSamplerState(const SamplerDescriptor*)`
22    pub fn new_sampler_state(&self, descriptor: &SamplerDescriptor) -> Option<SamplerState> {
23        unsafe {
24            let ptr: *mut c_void = msg_send_1(
25                self.as_ptr(),
26                sel!(newSamplerStateWithDescriptor:),
27                descriptor.as_ptr(),
28            );
29            SamplerState::from_raw(ptr)
30        }
31    }
32
33    /// Create a sampler state with validation.
34    ///
35    /// This safe method validates the descriptor before calling Metal APIs:
36    /// - Ensures LOD min clamp is <= LOD max clamp
37    /// - Ensures max anisotropy is >= 1 and a power of 2
38    ///
39    /// # Example
40    ///
41    /// ```ignore
42    /// let desc = SamplerDescriptor::new().unwrap();
43    /// desc.set_min_filter(SamplerMinMagFilter::LINEAR);
44    /// desc.set_mag_filter(SamplerMinMagFilter::LINEAR);
45    ///
46    /// match device.new_sampler_state_validated(&desc) {
47    ///     Ok(sampler) => { /* use sampler */ }
48    ///     Err(ValidationError::InvalidLodRange { .. }) => { /* handle error */ }
49    ///     Err(e) => { /* handle other errors */ }
50    /// }
51    /// ```
52    pub fn new_sampler_state_validated(
53        &self,
54        descriptor: &SamplerDescriptor,
55    ) -> Result<SamplerState, ValidationError> {
56        // Validate LOD range
57        let min_lod = descriptor.lod_min_clamp();
58        let max_lod = descriptor.lod_max_clamp();
59        if min_lod > max_lod {
60            return Err(ValidationError::InvalidLodRange {
61                min: min_lod,
62                max: max_lod,
63            });
64        }
65
66        // Validate anisotropy
67        let anisotropy = descriptor.max_anisotropy();
68        if anisotropy < 1 || !anisotropy.is_power_of_two() {
69            return Err(ValidationError::InvalidAnisotropy(anisotropy));
70        }
71
72        // Call existing safe implementation
73        self.new_sampler_state(descriptor)
74            .ok_or(ValidationError::CreationFailed(None))
75    }
76
77    /// Create a new sampler state with a raw descriptor pointer.
78    ///
79    /// C++ equivalent: `SamplerState* newSamplerState(const SamplerDescriptor*)`
80    ///
81    /// # Safety
82    ///
83    /// The descriptor pointer must be valid.
84    pub unsafe fn new_sampler_state_with_ptr(
85        &self,
86        descriptor: *const c_void,
87    ) -> Option<SamplerState> {
88        unsafe {
89            let ptr: *mut c_void = msg_send_1(
90                self.as_ptr(),
91                sel!(newSamplerStateWithDescriptor:),
92                descriptor,
93            );
94            SamplerState::from_raw(ptr)
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::device::system_default;
103    use crate::enums::{SamplerMinMagFilter, SamplerMipFilter};
104
105    #[test]
106    fn test_new_sampler_state() {
107        let device = system_default().expect("no Metal device");
108        let descriptor = SamplerDescriptor::new().expect("failed to create descriptor");
109
110        descriptor.set_min_filter(SamplerMinMagFilter::LINEAR);
111        descriptor.set_mag_filter(SamplerMinMagFilter::LINEAR);
112        descriptor.set_mip_filter(SamplerMipFilter::LINEAR);
113
114        let sampler = device.new_sampler_state(&descriptor);
115        assert!(sampler.is_some());
116    }
117}