mtl_gpu/device/limits.rs
1//! Device limits and alignment queries.
2//!
3//! Corresponds to limit query methods in `MTL::Device` from `Metal/MTLDevice.hpp`.
4
5use std::ffi::c_void;
6
7use mtl_foundation::{Referencing, UInteger};
8use mtl_sys::{msg_send_0, msg_send_1, msg_send_2, msg_send_3, msg_send_4, sel};
9
10use super::Device;
11use crate::enums::{
12 PixelFormat, ResourceOptions, SparsePageSize, SparseTextureRegionAlignmentMode, TextureType,
13};
14use crate::types::{Region, Size, SizeAndAlign};
15
16impl Device {
17 // =========================================================================
18 // Thread Limits
19 // =========================================================================
20
21 /// Get the maximum threads per threadgroup.
22 ///
23 /// C++ equivalent: `Size maxThreadsPerThreadgroup() const`
24 #[inline]
25 pub fn max_threads_per_threadgroup(&self) -> Size {
26 unsafe { msg_send_0(self.as_ptr(), sel!(maxThreadsPerThreadgroup)) }
27 }
28
29 /// Get the maximum threadgroup memory length in bytes.
30 ///
31 /// C++ equivalent: `NS::UInteger maxThreadgroupMemoryLength() const`
32 #[inline]
33 pub fn max_threadgroup_memory_length(&self) -> UInteger {
34 unsafe { msg_send_0(self.as_ptr(), sel!(maxThreadgroupMemoryLength)) }
35 }
36
37 // =========================================================================
38 // Buffer Limits
39 // =========================================================================
40
41 /// Get the maximum buffer length in bytes.
42 ///
43 /// C++ equivalent: `NS::UInteger maxBufferLength() const`
44 #[inline]
45 pub fn max_buffer_length(&self) -> UInteger {
46 unsafe { msg_send_0(self.as_ptr(), sel!(maxBufferLength)) }
47 }
48
49 // =========================================================================
50 // Argument Buffer Limits
51 // =========================================================================
52
53 /// Get the maximum number of samplers that can be in an argument buffer.
54 ///
55 /// C++ equivalent: `NS::UInteger maxArgumentBufferSamplerCount() const`
56 #[inline]
57 pub fn max_argument_buffer_sampler_count(&self) -> UInteger {
58 unsafe { msg_send_0(self.as_ptr(), sel!(maxArgumentBufferSamplerCount)) }
59 }
60
61 // =========================================================================
62 // Texture Alignment
63 // =========================================================================
64
65 /// Get the minimum alignment for a linear texture with the given pixel format.
66 ///
67 /// C++ equivalent: `NS::UInteger minimumLinearTextureAlignmentForPixelFormat(MTL::PixelFormat format)`
68 #[inline]
69 pub fn minimum_linear_texture_alignment_for_pixel_format(
70 &self,
71 format: PixelFormat,
72 ) -> UInteger {
73 unsafe {
74 msg_send_1(
75 self.as_ptr(),
76 sel!(minimumLinearTextureAlignmentForPixelFormat:),
77 format,
78 )
79 }
80 }
81
82 /// Get the minimum alignment for a texture buffer with the given pixel format.
83 ///
84 /// C++ equivalent: `NS::UInteger minimumTextureBufferAlignmentForPixelFormat(MTL::PixelFormat format)`
85 #[inline]
86 pub fn minimum_texture_buffer_alignment_for_pixel_format(
87 &self,
88 format: PixelFormat,
89 ) -> UInteger {
90 unsafe {
91 msg_send_1(
92 self.as_ptr(),
93 sel!(minimumTextureBufferAlignmentForPixelFormat:),
94 format,
95 )
96 }
97 }
98
99 // =========================================================================
100 // Sparse Texture Support
101 // =========================================================================
102
103 /// Get the sparse tile size in bytes.
104 ///
105 /// C++ equivalent: `NS::UInteger sparseTileSizeInBytes() const`
106 #[inline]
107 pub fn sparse_tile_size_in_bytes(&self) -> UInteger {
108 unsafe { msg_send_0(self.as_ptr(), sel!(sparseTileSizeInBytes)) }
109 }
110
111 /// Get the sparse tile size in bytes for a specific page size.
112 ///
113 /// C++ equivalent: `NS::UInteger sparseTileSizeInBytes(MTL::SparsePageSize sparsePageSize)`
114 #[inline]
115 pub fn sparse_tile_size_in_bytes_for_page_size(&self, page_size: SparsePageSize) -> UInteger {
116 unsafe {
117 msg_send_1(
118 self.as_ptr(),
119 sel!(sparseTileSizeInBytesForSparsePageSize:),
120 page_size,
121 )
122 }
123 }
124
125 /// Get the sparse tile size for a texture configuration.
126 ///
127 /// C++ equivalent: `Size sparseTileSize(MTL::TextureType, MTL::PixelFormat, NS::UInteger sampleCount)`
128 #[inline]
129 pub fn sparse_tile_size(
130 &self,
131 texture_type: TextureType,
132 pixel_format: PixelFormat,
133 sample_count: UInteger,
134 ) -> Size {
135 unsafe {
136 msg_send_3(
137 self.as_ptr(),
138 sel!(sparseTileSizeWithTextureType: pixelFormat: sampleCount:),
139 texture_type,
140 pixel_format,
141 sample_count,
142 )
143 }
144 }
145
146 /// Get the sparse tile size for a texture configuration with specific page size.
147 ///
148 /// C++ equivalent: `Size sparseTileSize(MTL::TextureType, MTL::PixelFormat, NS::UInteger, MTL::SparsePageSize)`
149 #[inline]
150 pub fn sparse_tile_size_with_page_size(
151 &self,
152 texture_type: TextureType,
153 pixel_format: PixelFormat,
154 sample_count: UInteger,
155 page_size: SparsePageSize,
156 ) -> Size {
157 unsafe {
158 msg_send_4(
159 self.as_ptr(),
160 sel!(sparseTileSizeWithTextureType: pixelFormat: sampleCount: sparsePageSize:),
161 texture_type,
162 pixel_format,
163 sample_count,
164 page_size,
165 )
166 }
167 }
168
169 /// Convert pixel regions to tile regions for sparse textures.
170 ///
171 /// C++ equivalent: `void convertSparsePixelRegions(...)`
172 pub fn convert_sparse_pixel_regions(
173 &self,
174 pixel_regions: &[Region],
175 tile_regions: &mut [Region],
176 tile_size: Size,
177 mode: SparseTextureRegionAlignmentMode,
178 ) {
179 assert_eq!(pixel_regions.len(), tile_regions.len());
180 unsafe {
181 mtl_sys::msg_send_5::<
182 (),
183 *const Region,
184 *mut Region,
185 Size,
186 SparseTextureRegionAlignmentMode,
187 usize,
188 >(
189 self.as_ptr(),
190 sel!(convertSparsePixelRegions: toTileRegions: withTileSize: alignmentMode: numRegions:),
191 pixel_regions.as_ptr(),
192 tile_regions.as_mut_ptr(),
193 tile_size,
194 mode,
195 pixel_regions.len(),
196 );
197 }
198 }
199
200 /// Convert tile regions to pixel regions for sparse textures.
201 ///
202 /// C++ equivalent: `void convertSparseTileRegions(...)`
203 pub fn convert_sparse_tile_regions(
204 &self,
205 tile_regions: &[Region],
206 pixel_regions: &mut [Region],
207 tile_size: Size,
208 ) {
209 assert_eq!(tile_regions.len(), pixel_regions.len());
210 unsafe {
211 msg_send_4::<(), *const Region, *mut Region, Size, usize>(
212 self.as_ptr(),
213 sel!(convertSparseTileRegions: toPixelRegions: withTileSize: numRegions:),
214 tile_regions.as_ptr(),
215 pixel_regions.as_mut_ptr(),
216 tile_size,
217 tile_regions.len(),
218 );
219 }
220 }
221
222 // =========================================================================
223 // Heap Size and Alignment
224 // =========================================================================
225
226 /// Get the size and alignment for a buffer in a heap.
227 ///
228 /// C++ equivalent: `SizeAndAlign heapBufferSizeAndAlign(NS::UInteger length, MTL::ResourceOptions options)`
229 #[inline]
230 pub fn heap_buffer_size_and_align(
231 &self,
232 length: UInteger,
233 options: ResourceOptions,
234 ) -> SizeAndAlign {
235 unsafe {
236 msg_send_2(
237 self.as_ptr(),
238 sel!(heapBufferSizeAndAlignWithLength: options:),
239 length,
240 options,
241 )
242 }
243 }
244
245 /// Get the size and alignment for a texture in a heap.
246 ///
247 /// C++ equivalent: `SizeAndAlign heapTextureSizeAndAlign(const MTL::TextureDescriptor* desc)`
248 ///
249 /// # Safety
250 ///
251 /// The descriptor pointer must be a valid MTLTextureDescriptor.
252 #[inline]
253 pub unsafe fn heap_texture_size_and_align(&self, descriptor: *const c_void) -> SizeAndAlign {
254 unsafe {
255 msg_send_1(
256 self.as_ptr(),
257 sel!(heapTextureSizeAndAlignWithDescriptor:),
258 descriptor,
259 )
260 }
261 }
262
263 /// Get the size and alignment for an acceleration structure in a heap (by size).
264 ///
265 /// C++ equivalent: `SizeAndAlign heapAccelerationStructureSizeAndAlign(NS::UInteger size)`
266 #[inline]
267 pub fn heap_acceleration_structure_size_and_align_with_size(
268 &self,
269 size: UInteger,
270 ) -> SizeAndAlign {
271 unsafe {
272 msg_send_1(
273 self.as_ptr(),
274 sel!(heapAccelerationStructureSizeAndAlignWithSize:),
275 size,
276 )
277 }
278 }
279
280 /// Get the size and alignment for an acceleration structure in a heap (by descriptor).
281 ///
282 /// C++ equivalent: `SizeAndAlign heapAccelerationStructureSizeAndAlign(const MTL::AccelerationStructureDescriptor*)`
283 ///
284 /// # Safety
285 ///
286 /// The descriptor pointer must be a valid MTLAccelerationStructureDescriptor.
287 #[inline]
288 pub unsafe fn heap_acceleration_structure_size_and_align_with_descriptor(
289 &self,
290 descriptor: *const c_void,
291 ) -> SizeAndAlign {
292 unsafe {
293 msg_send_1(
294 self.as_ptr(),
295 sel!(heapAccelerationStructureSizeAndAlignWithDescriptor:),
296 descriptor,
297 )
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 use crate::device::system_default;
306
307 #[test]
308 fn test_buffer_limits() {
309 let device = system_default().expect("no Metal device");
310
311 let max_buffer = device.max_buffer_length();
312 assert!(max_buffer > 0, "max buffer length should be positive");
313 println!("Max buffer length: {} bytes", max_buffer);
314 }
315
316 #[test]
317 fn test_thread_limits() {
318 let device = system_default().expect("no Metal device");
319
320 let max_threads = device.max_threads_per_threadgroup();
321 let w = { max_threads.width };
322 let h = { max_threads.height };
323 let d = { max_threads.depth };
324 assert!(w > 0 && h > 0 && d > 0);
325 println!("Max threads per threadgroup: {}x{}x{}", w, h, d);
326
327 let max_tg_memory = device.max_threadgroup_memory_length();
328 assert!(max_tg_memory > 0);
329 println!("Max threadgroup memory: {} bytes", max_tg_memory);
330 }
331
332 #[test]
333 fn test_texture_alignment() {
334 let device = system_default().expect("no Metal device");
335
336 let alignment =
337 device.minimum_linear_texture_alignment_for_pixel_format(PixelFormat::RGBA8_UNORM);
338 assert!(alignment > 0);
339 println!("RGBA8 linear texture alignment: {} bytes", alignment);
340 }
341}