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}