Skip to main content

mtl_gpu/device/
features.rs

1//! Device feature queries.
2//!
3//! Corresponds to feature query methods in `MTL::Device` from `Metal/MTLDevice.hpp`.
4
5use mtl_foundation::{Referencing, UInteger};
6use mtl_sys::{msg_send_0, msg_send_1, sel};
7
8use super::Device;
9use crate::enums::{CounterSamplingPoint, FeatureSet, GPUFamily};
10
11impl Device {
12    // =========================================================================
13    // GPU Family Support
14    // =========================================================================
15
16    /// Check if the device supports a specific GPU family.
17    ///
18    /// C++ equivalent: `bool supportsFamily(MTL::GPUFamily gpuFamily)`
19    #[inline]
20    pub fn supports_family(&self, gpu_family: GPUFamily) -> bool {
21        unsafe { msg_send_1(self.as_ptr(), sel!(supportsFamily:), gpu_family) }
22    }
23
24    /// Check if the device supports a specific feature set (legacy).
25    ///
26    /// C++ equivalent: `bool supportsFeatureSet(MTL::FeatureSet featureSet)`
27    #[inline]
28    pub fn supports_feature_set(&self, feature_set: FeatureSet) -> bool {
29        unsafe { msg_send_1(self.as_ptr(), sel!(supportsFeatureSet:), feature_set) }
30    }
31
32    // =========================================================================
33    // Rendering Features
34    // =========================================================================
35
36    /// Check if barycentric coordinates are supported.
37    ///
38    /// C++ equivalent: `bool areBarycentricCoordsSupported() const`
39    #[inline]
40    pub fn are_barycentric_coords_supported(&self) -> bool {
41        unsafe { msg_send_0(self.as_ptr(), sel!(areBarycentricCoordsSupported)) }
42    }
43
44    /// Check if programmable sample positions are supported.
45    ///
46    /// C++ equivalent: `bool areProgrammableSamplePositionsSupported() const`
47    #[inline]
48    pub fn are_programmable_sample_positions_supported(&self) -> bool {
49        unsafe { msg_send_0(self.as_ptr(), sel!(areProgrammableSamplePositionsSupported)) }
50    }
51
52    /// Check if raster order groups are supported.
53    ///
54    /// C++ equivalent: `bool areRasterOrderGroupsSupported() const`
55    #[inline]
56    pub fn are_raster_order_groups_supported(&self) -> bool {
57        unsafe { msg_send_0(self.as_ptr(), sel!(areRasterOrderGroupsSupported)) }
58    }
59
60    /// Check if 32-bit float filtering is supported.
61    ///
62    /// C++ equivalent: `bool supports32BitFloatFiltering() const`
63    #[inline]
64    pub fn supports_32bit_float_filtering(&self) -> bool {
65        unsafe { msg_send_0(self.as_ptr(), sel!(supports32BitFloatFiltering)) }
66    }
67
68    /// Check if 32-bit MSAA is supported.
69    ///
70    /// C++ equivalent: `bool supports32BitMSAA() const`
71    #[inline]
72    pub fn supports_32bit_msaa(&self) -> bool {
73        unsafe { msg_send_0(self.as_ptr(), sel!(supports32BitMSAA)) }
74    }
75
76    /// Check if the device supports a specific texture sample count.
77    ///
78    /// C++ equivalent: `bool supportsTextureSampleCount(NS::UInteger sampleCount)`
79    #[inline]
80    pub fn supports_texture_sample_count(&self, sample_count: UInteger) -> bool {
81        unsafe {
82            msg_send_1(
83                self.as_ptr(),
84                sel!(supportsTextureSampleCount:),
85                sample_count,
86            )
87        }
88    }
89
90    /// Check if vertex amplification is supported for a given count.
91    ///
92    /// C++ equivalent: `bool supportsVertexAmplificationCount(NS::UInteger count)`
93    #[inline]
94    pub fn supports_vertex_amplification_count(&self, count: UInteger) -> bool {
95        unsafe {
96            msg_send_1(
97                self.as_ptr(),
98                sel!(supportsVertexAmplificationCount:),
99                count,
100            )
101        }
102    }
103
104    /// Check if query texture LOD is supported.
105    ///
106    /// C++ equivalent: `bool supportsQueryTextureLOD() const`
107    #[inline]
108    pub fn supports_query_texture_lod(&self) -> bool {
109        unsafe { msg_send_0(self.as_ptr(), sel!(supportsQueryTextureLOD)) }
110    }
111
112    /// Check if pull model interpolation is supported.
113    ///
114    /// C++ equivalent: `bool supportsPullModelInterpolation() const`
115    #[inline]
116    pub fn supports_pull_model_interpolation(&self) -> bool {
117        unsafe { msg_send_0(self.as_ptr(), sel!(supportsPullModelInterpolation)) }
118    }
119
120    /// Check if shader barycentric coordinates are supported.
121    ///
122    /// C++ equivalent: `bool supportsShaderBarycentricCoordinates() const`
123    #[inline]
124    pub fn supports_shader_barycentric_coordinates(&self) -> bool {
125        unsafe { msg_send_0(self.as_ptr(), sel!(supportsShaderBarycentricCoordinates)) }
126    }
127
128    // =========================================================================
129    // Texture Features
130    // =========================================================================
131
132    /// Check if BC texture compression is supported.
133    ///
134    /// C++ equivalent: `bool supportsBCTextureCompression() const`
135    #[inline]
136    pub fn supports_bc_texture_compression(&self) -> bool {
137        unsafe { msg_send_0(self.as_ptr(), sel!(supportsBCTextureCompression)) }
138    }
139
140    /// Check if depth24 stencil8 pixel format is supported.
141    ///
142    /// C++ equivalent: `bool isDepth24Stencil8PixelFormatSupported() const`
143    #[inline]
144    pub fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
145        unsafe { msg_send_0(self.as_ptr(), sel!(isDepth24Stencil8PixelFormatSupported)) }
146    }
147
148    // =========================================================================
149    // Ray Tracing Features
150    // =========================================================================
151
152    /// Check if ray tracing is supported.
153    ///
154    /// C++ equivalent: `bool supportsRaytracing() const`
155    #[inline]
156    pub fn supports_raytracing(&self) -> bool {
157        unsafe { msg_send_0(self.as_ptr(), sel!(supportsRaytracing)) }
158    }
159
160    /// Check if ray tracing from render is supported.
161    ///
162    /// C++ equivalent: `bool supportsRaytracingFromRender() const`
163    #[inline]
164    pub fn supports_raytracing_from_render(&self) -> bool {
165        unsafe { msg_send_0(self.as_ptr(), sel!(supportsRaytracingFromRender)) }
166    }
167
168    /// Check if primitive motion blur is supported.
169    ///
170    /// C++ equivalent: `bool supportsPrimitiveMotionBlur() const`
171    #[inline]
172    pub fn supports_primitive_motion_blur(&self) -> bool {
173        unsafe { msg_send_0(self.as_ptr(), sel!(supportsPrimitiveMotionBlur)) }
174    }
175
176    // =========================================================================
177    // Function Features
178    // =========================================================================
179
180    /// Check if function pointers are supported.
181    ///
182    /// C++ equivalent: `bool supportsFunctionPointers() const`
183    #[inline]
184    pub fn supports_function_pointers(&self) -> bool {
185        unsafe { msg_send_0(self.as_ptr(), sel!(supportsFunctionPointers)) }
186    }
187
188    /// Check if function pointers from render are supported.
189    ///
190    /// C++ equivalent: `bool supportsFunctionPointersFromRender() const`
191    #[inline]
192    pub fn supports_function_pointers_from_render(&self) -> bool {
193        unsafe { msg_send_0(self.as_ptr(), sel!(supportsFunctionPointersFromRender)) }
194    }
195
196    /// Check if dynamic libraries are supported.
197    ///
198    /// C++ equivalent: `bool supportsDynamicLibraries() const`
199    #[inline]
200    pub fn supports_dynamic_libraries(&self) -> bool {
201        unsafe { msg_send_0(self.as_ptr(), sel!(supportsDynamicLibraries)) }
202    }
203
204    /// Check if render dynamic libraries are supported.
205    ///
206    /// C++ equivalent: `bool supportsRenderDynamicLibraries() const`
207    #[inline]
208    pub fn supports_render_dynamic_libraries(&self) -> bool {
209        unsafe { msg_send_0(self.as_ptr(), sel!(supportsRenderDynamicLibraries)) }
210    }
211
212    // =========================================================================
213    // Variable Rate Rendering Features
214    // =========================================================================
215
216    /// Check if rasterization rate maps are supported for a given layer count.
217    ///
218    /// C++ equivalent: `bool supportsRasterizationRateMap(NS::UInteger layerCount)`
219    #[inline]
220    pub fn supports_rasterization_rate_map(&self, layer_count: UInteger) -> bool {
221        unsafe {
222            msg_send_1(
223                self.as_ptr(),
224                sel!(supportsRasterizationRateMapWithLayerCount:),
225                layer_count,
226            )
227        }
228    }
229
230    // =========================================================================
231    // Counter Sampling Features
232    // =========================================================================
233
234    /// Check if counter sampling is supported at a specific sampling point.
235    ///
236    /// C++ equivalent: `bool supportsCounterSampling(MTL::CounterSamplingPoint samplingPoint)`
237    #[inline]
238    pub fn supports_counter_sampling(&self, sampling_point: CounterSamplingPoint) -> bool {
239        unsafe {
240            msg_send_1(
241                self.as_ptr(),
242                sel!(supportsCounterSampling:),
243                sampling_point,
244            )
245        }
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use crate::device::system_default;
253
254    #[test]
255    fn test_feature_queries() {
256        let device = system_default().expect("no Metal device");
257
258        // Metal 3 should be supported on modern Apple Silicon
259        let supports_metal3 = device.supports_family(GPUFamily::METAL3);
260        println!("Supports Metal 3: {}", supports_metal3);
261
262        // Check raytracing support
263        let supports_raytracing = device.supports_raytracing();
264        println!("Supports raytracing: {}", supports_raytracing);
265
266        // Check unified memory
267        let unified = device.has_unified_memory();
268        println!("Has unified memory: {}", unified);
269    }
270
271    #[test]
272    fn test_sample_count_support() {
273        let device = system_default().expect("no Metal device");
274
275        // Most devices support 1, 2, 4, and 8 samples
276        assert!(device.supports_texture_sample_count(1));
277        assert!(device.supports_texture_sample_count(4));
278    }
279}