Skip to main content

mtl_gpu/library/
compile_options.rs

1//! Options for compiling shader source code.
2
3use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::{Referencing, UInteger};
7use mtl_sys::{msg_send_0, msg_send_1, sel};
8
9use crate::enums::{
10    CompileSymbolVisibility, LanguageVersion, LibraryOptimizationLevel, LibraryType,
11    MathFloatingPointFunctions, MathMode,
12};
13use crate::types::Size;
14
15/// Options for compiling shader source code.
16///
17/// C++ equivalent: `MTL::CompileOptions`
18#[repr(transparent)]
19pub struct CompileOptions(pub(crate) NonNull<c_void>);
20
21impl CompileOptions {
22    /// Create new compile options.
23    ///
24    /// C++ equivalent: `static CompileOptions* alloc()->init()`
25    pub fn new() -> Option<Self> {
26        unsafe {
27            let class = mtl_sys::Class::get("MTLCompileOptions")?;
28            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
29            if ptr.is_null() {
30                return None;
31            }
32            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
33            Self::from_raw(ptr)
34        }
35    }
36
37    /// Create a CompileOptions from a raw pointer.
38    ///
39    /// # Safety
40    ///
41    /// The pointer must be a valid Metal compile options object.
42    #[inline]
43    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
44        NonNull::new(ptr).map(Self)
45    }
46
47    /// Get the raw pointer.
48    #[inline]
49    pub fn as_raw(&self) -> *mut c_void {
50        self.0.as_ptr()
51    }
52
53    /// Get whether fast math is enabled.
54    ///
55    /// C++ equivalent: `bool fastMathEnabled() const`
56    #[inline]
57    pub fn fast_math_enabled(&self) -> bool {
58        unsafe { msg_send_0(self.as_ptr(), sel!(fastMathEnabled)) }
59    }
60
61    /// Set whether fast math is enabled.
62    ///
63    /// C++ equivalent: `void setFastMathEnabled(bool)`
64    #[inline]
65    pub fn set_fast_math_enabled(&self, enabled: bool) {
66        unsafe {
67            msg_send_1::<(), bool>(self.as_ptr(), sel!(setFastMathEnabled:), enabled);
68        }
69    }
70
71    /// Get the language version.
72    ///
73    /// C++ equivalent: `LanguageVersion languageVersion() const`
74    #[inline]
75    pub fn language_version(&self) -> LanguageVersion {
76        unsafe { msg_send_0(self.as_ptr(), sel!(languageVersion)) }
77    }
78
79    /// Set the language version.
80    ///
81    /// C++ equivalent: `void setLanguageVersion(LanguageVersion)`
82    #[inline]
83    pub fn set_language_version(&self, version: LanguageVersion) {
84        unsafe {
85            msg_send_1::<(), LanguageVersion>(self.as_ptr(), sel!(setLanguageVersion:), version);
86        }
87    }
88
89    /// Get whether to preserve invariance.
90    ///
91    /// C++ equivalent: `bool preserveInvariance() const`
92    #[inline]
93    pub fn preserve_invariance(&self) -> bool {
94        unsafe { msg_send_0(self.as_ptr(), sel!(preserveInvariance)) }
95    }
96
97    /// Set whether to preserve invariance.
98    ///
99    /// C++ equivalent: `void setPreserveInvariance(bool)`
100    #[inline]
101    pub fn set_preserve_invariance(&self, preserve: bool) {
102        unsafe {
103            msg_send_1::<(), bool>(self.as_ptr(), sel!(setPreserveInvariance:), preserve);
104        }
105    }
106
107    /// Get the optimization level.
108    ///
109    /// C++ equivalent: `LibraryOptimizationLevel optimizationLevel() const`
110    #[inline]
111    pub fn optimization_level(&self) -> LibraryOptimizationLevel {
112        unsafe { msg_send_0(self.as_ptr(), sel!(optimizationLevel)) }
113    }
114
115    /// Set the optimization level.
116    ///
117    /// C++ equivalent: `void setOptimizationLevel(MTL::LibraryOptimizationLevel)`
118    #[inline]
119    pub fn set_optimization_level(&self, level: LibraryOptimizationLevel) {
120        unsafe {
121            msg_send_1::<(), LibraryOptimizationLevel>(
122                self.as_ptr(),
123                sel!(setOptimizationLevel:),
124                level,
125            );
126        }
127    }
128
129    /// Get the math mode.
130    ///
131    /// C++ equivalent: `MathMode mathMode() const`
132    #[inline]
133    pub fn math_mode(&self) -> MathMode {
134        unsafe { msg_send_0(self.as_ptr(), sel!(mathMode)) }
135    }
136
137    /// Set the math mode.
138    ///
139    /// C++ equivalent: `void setMathMode(MTL::MathMode)`
140    #[inline]
141    pub fn set_math_mode(&self, mode: MathMode) {
142        unsafe {
143            msg_send_1::<(), MathMode>(self.as_ptr(), sel!(setMathMode:), mode);
144        }
145    }
146
147    /// Get the math floating point functions precision.
148    ///
149    /// C++ equivalent: `MathFloatingPointFunctions mathFloatingPointFunctions() const`
150    #[inline]
151    pub fn math_floating_point_functions(&self) -> MathFloatingPointFunctions {
152        unsafe { msg_send_0(self.as_ptr(), sel!(mathFloatingPointFunctions)) }
153    }
154
155    /// Set the math floating point functions precision.
156    ///
157    /// C++ equivalent: `void setMathFloatingPointFunctions(MTL::MathFloatingPointFunctions)`
158    #[inline]
159    pub fn set_math_floating_point_functions(&self, funcs: MathFloatingPointFunctions) {
160        unsafe {
161            msg_send_1::<(), MathFloatingPointFunctions>(
162                self.as_ptr(),
163                sel!(setMathFloatingPointFunctions:),
164                funcs,
165            );
166        }
167    }
168
169    /// Get the compile symbol visibility.
170    ///
171    /// C++ equivalent: `CompileSymbolVisibility compileSymbolVisibility() const`
172    #[inline]
173    pub fn compile_symbol_visibility(&self) -> CompileSymbolVisibility {
174        unsafe { msg_send_0(self.as_ptr(), sel!(compileSymbolVisibility)) }
175    }
176
177    /// Set the compile symbol visibility.
178    ///
179    /// C++ equivalent: `void setCompileSymbolVisibility(MTL::CompileSymbolVisibility)`
180    #[inline]
181    pub fn set_compile_symbol_visibility(&self, visibility: CompileSymbolVisibility) {
182        unsafe {
183            msg_send_1::<(), CompileSymbolVisibility>(
184                self.as_ptr(),
185                sel!(setCompileSymbolVisibility:),
186                visibility,
187            );
188        }
189    }
190
191    /// Get the library type.
192    ///
193    /// C++ equivalent: `LibraryType libraryType() const`
194    #[inline]
195    pub fn library_type(&self) -> LibraryType {
196        unsafe { msg_send_0(self.as_ptr(), sel!(libraryType)) }
197    }
198
199    /// Set the library type.
200    ///
201    /// C++ equivalent: `void setLibraryType(MTL::LibraryType)`
202    #[inline]
203    pub fn set_library_type(&self, lib_type: LibraryType) {
204        unsafe {
205            msg_send_1::<(), LibraryType>(self.as_ptr(), sel!(setLibraryType:), lib_type);
206        }
207    }
208
209    /// Get the install name (for dynamic libraries).
210    ///
211    /// C++ equivalent: `NS::String* installName() const`
212    pub fn install_name(&self) -> Option<String> {
213        unsafe {
214            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(installName));
215            if ptr.is_null() {
216                return None;
217            }
218            let utf8_ptr: *const std::ffi::c_char =
219                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
220            if utf8_ptr.is_null() {
221                return None;
222            }
223            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
224            Some(c_str.to_string_lossy().into_owned())
225        }
226    }
227
228    /// Set the install name (for dynamic libraries).
229    ///
230    /// C++ equivalent: `void setInstallName(const NS::String*)`
231    pub fn set_install_name(&self, name: &str) {
232        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
233            unsafe {
234                msg_send_1::<(), *const c_void>(
235                    self.as_ptr(),
236                    sel!(setInstallName:),
237                    ns_name.as_ptr(),
238                );
239            }
240        }
241    }
242
243    /// Get whether to allow referencing undefined symbols.
244    ///
245    /// C++ equivalent: `bool allowReferencingUndefinedSymbols() const`
246    #[inline]
247    pub fn allow_referencing_undefined_symbols(&self) -> bool {
248        unsafe { msg_send_0(self.as_ptr(), sel!(allowReferencingUndefinedSymbols)) }
249    }
250
251    /// Set whether to allow referencing undefined symbols.
252    ///
253    /// C++ equivalent: `void setAllowReferencingUndefinedSymbols(bool)`
254    #[inline]
255    pub fn set_allow_referencing_undefined_symbols(&self, allow: bool) {
256        unsafe {
257            msg_send_1::<(), bool>(
258                self.as_ptr(),
259                sel!(setAllowReferencingUndefinedSymbols:),
260                allow,
261            );
262        }
263    }
264
265    /// Get whether logging is enabled.
266    ///
267    /// C++ equivalent: `bool enableLogging() const`
268    #[inline]
269    pub fn enable_logging(&self) -> bool {
270        unsafe { msg_send_0(self.as_ptr(), sel!(enableLogging)) }
271    }
272
273    /// Set whether logging is enabled.
274    ///
275    /// C++ equivalent: `void setEnableLogging(bool)`
276    #[inline]
277    pub fn set_enable_logging(&self, enable: bool) {
278        unsafe {
279            msg_send_1::<(), bool>(self.as_ptr(), sel!(setEnableLogging:), enable);
280        }
281    }
282
283    /// Get the maximum total threads per threadgroup.
284    ///
285    /// C++ equivalent: `NS::UInteger maxTotalThreadsPerThreadgroup() const`
286    #[inline]
287    pub fn max_total_threads_per_threadgroup(&self) -> UInteger {
288        unsafe { msg_send_0(self.as_ptr(), sel!(maxTotalThreadsPerThreadgroup)) }
289    }
290
291    /// Set the maximum total threads per threadgroup.
292    ///
293    /// C++ equivalent: `void setMaxTotalThreadsPerThreadgroup(NS::UInteger)`
294    #[inline]
295    pub fn set_max_total_threads_per_threadgroup(&self, count: UInteger) {
296        unsafe {
297            msg_send_1::<(), UInteger>(
298                self.as_ptr(),
299                sel!(setMaxTotalThreadsPerThreadgroup:),
300                count,
301            );
302        }
303    }
304
305    /// Get the required threads per threadgroup.
306    ///
307    /// C++ equivalent: `Size requiredThreadsPerThreadgroup() const`
308    #[inline]
309    pub fn required_threads_per_threadgroup(&self) -> Size {
310        unsafe { msg_send_0(self.as_ptr(), sel!(requiredThreadsPerThreadgroup)) }
311    }
312
313    /// Set the required threads per threadgroup.
314    ///
315    /// C++ equivalent: `void setRequiredThreadsPerThreadgroup(MTL::Size)`
316    #[inline]
317    pub fn set_required_threads_per_threadgroup(&self, size: Size) {
318        unsafe {
319            msg_send_1::<(), Size>(self.as_ptr(), sel!(setRequiredThreadsPerThreadgroup:), size);
320        }
321    }
322
323    /// Get the preprocessor macros dictionary.
324    ///
325    /// Returns the dictionary of preprocessor macros as a raw pointer.
326    /// Use `mtl_foundation::Dictionary` to work with the returned value.
327    ///
328    /// C++ equivalent: `NS::Dictionary* preprocessorMacros() const`
329    pub fn preprocessor_macros_raw(&self) -> *mut c_void {
330        unsafe { msg_send_0(self.as_ptr(), sel!(preprocessorMacros)) }
331    }
332
333    /// Set the preprocessor macros dictionary.
334    ///
335    /// Takes a raw pointer to an NSDictionary containing the preprocessor macros.
336    ///
337    /// C++ equivalent: `void setPreprocessorMacros(const NS::Dictionary*)`
338    ///
339    /// # Safety
340    ///
341    /// The dictionary pointer must be valid or null.
342    pub unsafe fn set_preprocessor_macros_raw(&self, dict: *const c_void) {
343        unsafe {
344            msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setPreprocessorMacros:), dict);
345        }
346    }
347}
348
349impl Default for CompileOptions {
350    fn default() -> Self {
351        Self::new().expect("failed to create compile options")
352    }
353}
354
355impl Clone for CompileOptions {
356    fn clone(&self) -> Self {
357        unsafe {
358            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
359            Self::from_raw(ptr).expect("failed to copy compile options")
360        }
361    }
362}
363
364impl Drop for CompileOptions {
365    fn drop(&mut self) {
366        unsafe {
367            msg_send_0::<()>(self.as_ptr(), sel!(release));
368        }
369    }
370}
371
372impl Referencing for CompileOptions {
373    #[inline]
374    fn as_ptr(&self) -> *const c_void {
375        self.0.as_ptr()
376    }
377}
378
379unsafe impl Send for CompileOptions {}
380unsafe impl Sync for CompileOptions {}