spirv_cross2/compile/msl/mod.rs
1use crate::compile::{CommonOptions, CompiledArtifact};
2use spirv_cross_sys as sys;
3
4/// An MSL `constexpr` inlined sampler.
5pub use spirv_cross_sys::MslConstexprSampler as ConstexprSampler;
6
7/// Sampler addressing mode for inlined samplers.
8pub use spirv_cross_sys::MslSamplerAddress as SamplerAddress;
9/// Sampler border color for inlined samplers.
10pub use spirv_cross_sys::MslSamplerBorderColor as SamplerBorderColor;
11/// Sampler compare function for inline samplers.
12pub use spirv_cross_sys::MslSamplerCompareFunc as SamplerCompareFunc;
13/// Whether texture coordinates are normalized or not for inline samplers.
14pub use spirv_cross_sys::MslSamplerCoord as SamplerCoord;
15/// Mag and min filter mode for inline samplers.
16pub use spirv_cross_sys::MslSamplerFilter as SamplerFilter;
17/// Mip filtering mode for inline samplers.
18pub use spirv_cross_sys::MslSamplerMipFilter as SamplerMipFilter;
19
20/// Y′CbCr chroma location.
21pub use spirv_cross_sys::MslChromaLocation as YcbcrChromaLocation;
22/// Y′CbCr conversion component swizzle.
23pub use spirv_cross_sys::MslComponentSwizzle as YcbcrComponentSwizzle;
24/// Y′CbCr conversion format resolution.
25pub use spirv_cross_sys::MslFormatResolution as YcbcrFormatResolution;
26/// Y′CbCr model conversion options for inline samplers.
27pub use spirv_cross_sys::MslSamplerYcbcrConversion as SamplerYcbcrConversion;
28/// Format to convert when converting Y′CbCr.
29pub use spirv_cross_sys::MslSamplerYcbcrModelConversion as YcbcrTargetFormat;
30
31/// Conversion range for Y′CbCr.
32pub use spirv_cross_sys::MslSamplerYcbcrRange as YcbcrConversionRange;
33
34/// Indicates the format of a shader interface variable. Currently limited to specifying
35/// if the input is an 8-bit unsigned integer, 16-bit unsigned integer, or
36/// some other format.
37pub use spirv_cross_sys::MslShaderVariableFormat as ShaderVariableFormat;
38
39/// Indicates the rate at which a variable changes value, one of: per-vertex,
40/// per-primitive, or per-patch.
41pub use spirv_cross_sys::MslShaderVariableRate as ShaderVariableRate;
42
43/// Maximum number of argument buffers supported.
44pub const MAX_ARGUMENT_BUFFERS: u32 = 8;
45
46use crate::error::ToContextError;
47use crate::handle::{Handle, VariableId};
48use crate::sealed::Sealed;
49use crate::string::CompilerStr;
50use crate::targets::Msl;
51use crate::{error, Compiler, ContextRooted};
52use spirv_cross_sys::{MslResourceBinding2, MslShaderInterfaceVar2, SpvBuiltIn, SpvExecutionModel};
53use std::fmt::{Debug, Formatter};
54use std::num::NonZeroU32;
55
56impl Sealed for CompilerOptions {}
57/// MSL compiler options
58#[non_exhaustive]
59#[derive(Debug, spirv_cross2_derive::CompilerOptions)]
60pub struct CompilerOptions {
61 /// Compile options common to GLSL, HLSL, and MSL.
62 #[expand]
63 pub common: CommonOptions,
64
65 /// The MSL version to compile to.
66 ///
67 /// Defaults to MSL 1.2.
68 #[option(SPVC_COMPILER_OPTION_MSL_VERSION)]
69 pub version: MslVersion,
70
71 /// Width of 2D Metal textures used as 1D texel buffers.
72 #[option(SPVC_COMPILER_OPTION_MSL_TEXEL_BUFFER_TEXTURE_WIDTH, 4096)]
73 pub texel_buffer_texture_width: u32,
74
75 /// Index of the swizzle buffer.
76 ///
77 /// The default is 30.
78 #[option(SPVC_COMPILER_OPTION_MSL_SWIZZLE_BUFFER_INDEX, 30)]
79 pub swizzle_buffer_index: u32,
80
81 /// Index of the indirect params buffer.
82 ///
83 /// The default is 29.
84 #[option(SPVC_COMPILER_OPTION_MSL_INDIRECT_PARAMS_BUFFER_INDEX, 29)]
85 pub indirect_params_buffer_index: u32,
86
87 /// Index of the shader output buffer.
88 ///
89 /// The default is 28.
90 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_OUTPUT_BUFFER_INDEX, 28)]
91 pub shader_output_buffer_index: u32,
92
93 /// Index of the shader patch output buffer.
94 ///
95 /// The default is 27.
96 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_OUTPUT_BUFFER_INDEX, 27)]
97 pub shader_patch_output_buffer_index: u32,
98
99 /// Index of the shader tesselation factor output buffer.
100 ///
101 /// The default is 26.
102 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_TESS_FACTOR_OUTPUT_BUFFER_INDEX, 26)]
103 pub shader_tess_factor_output_buffer_index: u32,
104
105 /// Index of the buffer size buffer.
106 ///
107 /// The default is 25.
108 #[option(SPVC_COMPILER_OPTION_MSL_BUFFER_SIZE_BUFFER_INDEX, 25)]
109 pub buffer_size_buffer_index: u32,
110
111 /// Index of the view mask buffer.
112 ///
113 /// The default is 24
114 #[option(SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX, 24)]
115 pub view_mask_buffer_index: u32,
116
117 /// Index of the dynamic offsets buffer.
118 ///
119 /// The default is 23
120 #[option(SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX, 23)]
121 pub dynamic_offsets_buffer_index: u32,
122
123 /// Index of the shader input buffer.
124 ///
125 /// The default is 22.
126 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX, 22)]
127 pub shader_input_buffer_index: u32,
128
129 /// Index of the shader index buffer.
130 ///
131 /// The default is 21.
132 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX, 21)]
133 pub shader_index_buffer_index: u32,
134
135 /// Index of the shader patch input buffer.
136 ///
137 /// The default is 20.
138 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_INPUT_BUFFER_INDEX, 20)]
139 pub shader_patch_input_buffer_index: u32,
140
141 /// Index of the input workgroup index buffer.
142 ///
143 /// The default is 0
144 #[option(SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_WORKGROUP_INDEX, 0)]
145 pub shader_input_workgroup_index: u32,
146
147 /// Enable `point_size` builtin.
148 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_BUILTIN, true)]
149 pub enable_point_size_builtin: bool,
150
151 /// Enable the `FragDepth` builtin.
152 ///
153 /// Disable if pipeline does not enable depth, as pipeline
154 /// creation might otherwise fail.
155 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN, true)]
156 pub enable_frag_depth_builtin: bool,
157
158 /// Enable the `FragStencilRef` output.
159 ///
160 /// Disable if pipeline does not enable stencil output,
161 /// as pipeline creation might otherwise fail.
162 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN, true)]
163 pub enable_frag_stencil_ref_builtin: bool,
164
165 /// Disables rasterization and returns void from vertex-like entry points.
166 #[option(SPVC_COMPILER_OPTION_MSL_DISABLE_RASTERIZATION, false)]
167 pub disable_rasterization: bool,
168
169 /// Writes geometry varyings to a buffer instead of as stage-outputs.
170 #[option(SPVC_COMPILER_OPTION_MSL_CAPTURE_OUTPUT_TO_BUFFER, false)]
171 pub capture_output_to_buffer: bool,
172
173 /// Works around lack of support for VkImageView component swizzles.
174 /// Recent Metal versions do not require this workaround.
175 /// This has a massive impact on performance and bloat.
176 ///
177 /// Do not use this unless you are absolutely forced to.
178 ///
179 /// To use this feature, the API side must pass down swizzle buffers.
180 /// Should only be used by translation layers as a last resort.
181 #[option(SPVC_COMPILER_OPTION_MSL_SWIZZLE_TEXTURE_SAMPLES, false)]
182 pub swizzle_texture_samples: bool,
183
184 /// Always emit color outputs as 4-component variables.
185 ///
186 /// In Metal, the fragment shader must emit at least as many components
187 /// as the render target format.
188 #[option(SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS, false)]
189 pub pad_fragment_output_components: bool,
190
191 /// Use a lower-left tessellation domain.
192 #[option(SPVC_COMPILER_OPTION_MSL_TESS_DOMAIN_ORIGIN_LOWER_LEFT, false)]
193 pub tess_domain_origin_lower_left: bool,
194
195 /// The plattform to output MSL for. Defaults to macOS.
196 #[option(SPVC_COMPILER_OPTION_MSL_PLATFORM, MetalPlatform::MacOS)]
197 pub platform: MetalPlatform,
198
199 /// Enable use of Metal argument buffers.
200 ///
201 /// MSL 2.0 or higher must be used.
202 #[option(SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS, false)]
203 pub argument_buffers: bool,
204
205 /// Defines Metal argument buffer tier levels.
206 /// Uses same values as Metal `MTLArgumentBuffersTier` enumeration.
207 #[option(
208 SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS_TIER,
209 ArgumentBuffersTier::Tier1
210 )]
211 pub argument_buffers_tier: ArgumentBuffersTier,
212
213 /// Requires MSL 2.1, use the native support for texel buffers.
214 #[option(SPVC_COMPILER_OPTION_MSL_TEXTURE_BUFFER_NATIVE, false)]
215 pub texture_buffer_native: bool,
216
217 /// Enable SPV_KHR_multiview emulation.
218 #[option(SPVC_COMPILER_OPTION_MSL_MULTIVIEW, false)]
219 pub multiview: bool,
220
221 /// If disabled, don't set `[[render_target_array_index]]` in multiview shaders.
222 ///
223 /// Useful for devices which don't support layered rendering.
224 ///
225 /// Only effective when [`CompilerOptions::multiview`] is enabled.
226 #[option(SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING, true)]
227 pub multiview_layered_rendering: bool,
228
229 /// The index of the device
230 #[option(SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX, 0)]
231 pub device_index: u32,
232
233 /// Treat the view index as the device index instead. For multi-GPU rendering.
234 #[option(SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX, false)]
235 pub view_index_from_device_index: bool,
236
237 /// Add support for `vkCmdDispatchBase()` or similar APIs.
238 ///
239 /// Offsets the workgroup ID based on a buffer.
240 #[option(SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE, false)]
241 pub dispatch_base: bool,
242
243 /// Emit Image variables of dimension Dim1D as `texture2d`.
244 ///
245 /// In Metal, 1D textures do not support all features that 2D textures do.
246 ///
247 /// Use this option if your code relies on these features.
248 #[option(SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D, false)]
249 pub texture_1d_as_2d: bool,
250
251 /// Ensures vertex and instance indices start at zero.
252 ///
253 /// This reflects the behavior of HLSL with SV_VertexID and SV_InstanceID.
254 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO, false)]
255 pub enable_base_index_zero: bool,
256
257 /// Use Metal's native frame-buffer fetch API for subpass inputs.
258 #[option(SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS, false)]
259 pub framebuffer_fetch_subpass: bool,
260
261 /// Enables use of "fma" intrinsic for invariant float math
262 #[option(SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH, false)]
263 pub invariant_fp_math: bool,
264
265 /// Emulate texturecube_array with texture2d_array for iOS where this type is not available
266 #[option(SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY, false)]
267 pub emulate_cubemap_array: bool,
268
269 /// Allow user to enable decoration binding
270 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING, false)]
271 pub enable_decoration_binding: bool,
272
273 /// Forces all resources which are part of an argument buffer to be considered active.
274 ///
275 /// This ensures ABI compatibility between shaders where some resources might be unused,
276 /// and would otherwise declare a different ABI.
277 #[option(SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES, false)]
278 pub force_active_argument_buffer_resources: bool,
279
280 /// Forces the use of plain arrays, which works around certain driver bugs on certain versions
281 /// of Intel Macbooks.
282 ///
283 /// See <https://github.com/KhronosGroup/SPIRV-Cross/issues/1210>.
284 /// May reduce performance in scenarios where arrays are copied around as value-types.
285 #[option(SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS, false)]
286 pub force_native_arrays: bool,
287
288 /// Only selectively enable fragment outputs.
289 ///
290 /// Useful if pipeline does not enable
291 /// fragment output for certain locations, as pipeline creation might otherwise fail.
292 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK, 0xffffffff)]
293 pub enable_frag_output_mask: u32,
294
295 /// If a shader writes clip distance, also emit user varyings which
296 /// can be read in subsequent stages.
297 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING, true)]
298 pub enable_clip_distance_user_varying: bool,
299
300 /// In a tessellation control shader, assume that more than one patch can be processed in a
301 /// single workgroup. This requires changes to the way the InvocationId and PrimitiveId
302 /// builtins are processed, but should result in more efficient usage of the GPU.
303 #[option(SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP, false)]
304 pub multi_patch_workgroup: bool,
305
306 /// If set, a vertex shader will be compiled as part of a tessellation pipeline.
307 /// It will be translated as a compute kernel, so it can use the global invocation ID
308 /// to index the output buffer.
309 #[option(SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION, false)]
310 pub vertex_for_tessellation: bool,
311
312 /// The type of index in the index buffer, if present. For a compute shader, Metal
313 /// requires specifying the indexing at pipeline creation, rather than at draw time
314 /// as with graphics pipelines. This means we must create three different pipelines,
315 /// for no indexing, 16-bit indices, and 32-bit indices. Each requires different
316 /// handling for the gl_VertexIndex builtin. We may as well, then, create three
317 /// different shaders for these three scenarios.
318 #[option(SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE, IndexType::None)]
319 pub vertex_index_type: IndexType,
320
321 /// Assume that SubpassData images have multiple layers. Layered input attachments
322 /// are addressed relative to the Layer output from the vertex pipeline. This option
323 /// has no effect with multiview, since all input attachments are assumed to be layered
324 /// and will be addressed using the current ViewIndex.
325 #[option(SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT, false)]
326 pub arrayed_subpass_input: bool,
327
328 /// The required alignment of linear textures of format `MTLPixelFormatR32Uint`.
329 ///
330 /// This is used to align the row stride for atomic accesses to such images.
331 #[option(SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT, 4)]
332 pub r32ui_linear_texture_alignment: u32,
333
334 /// The function constant ID to use for the linear texture alignment.
335 ///
336 /// On MSL 1.2 or later, you can override the alignment by setting this function constant.
337 #[option(SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID, 65535)]
338 pub r32ui_alignment_constant_id: u32,
339
340 /// Whether to use SIMD-group or quadgroup functions to implement group non-uniform
341 /// operations. Some GPUs on iOS do not support the SIMD-group functions, only the
342 /// quadgroup functions.
343 #[option(SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS, false)]
344 pub ios_use_simdgroup_functions: bool,
345
346 /// If set, the subgroup size will be assumed to be one, and subgroup-related
347 /// builtins and operations will be emitted accordingly.
348 ///
349 /// This mode is intended to be used by MoltenVK on hardware/software configurations
350 /// which do not provide sufficient support for subgroups.
351 #[option(SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS, false)]
352 pub emulate_subgroups: bool,
353
354 /// If nonzero, a fixed subgroup size to assume. Metal, similarly to VK_EXT_subgroup_size_control,
355 /// allows the SIMD-group size (aka thread execution width) to vary depending on
356 /// register usage and requirements.
357 ///
358 /// In certain circumstances--for example, a pipeline
359 /// in MoltenVK without VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT--
360 /// this is undesirable. This fixes the value of the SubgroupSize builtin, instead of
361 /// mapping it to the Metal builtin `[[thread_execution_width]]`. If the thread
362 /// execution width is reduced, the extra invocations will appear to be inactive.
363 ///
364 /// If zero, the SubgroupSize will be allowed to vary, and the builtin will be mapped
365 /// to the Metal `[[thread_execution_width]]` builtin.
366 #[option(SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE, 0)]
367 pub fixed_subgroup_size: u32,
368
369 /// If set, a dummy `[[sample_id]]` input is added to a fragment shader if none is present.
370 ///
371 /// This will force the shader to run at sample rate, assuming Metal does not optimize
372 /// the extra threads away.
373 #[option(SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING, false)]
374 pub force_sample_rate_shading: bool,
375
376 /// Specifies whether the iOS target version supports the `[[base_vertex]]`
377 /// and `[[base_instance]]` attributes.
378 #[option(SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE, false)]
379 pub ios_support_base_vertex_instance: bool,
380
381 /// Use storage buffers instead of vertex-style attributes for tessellation evaluation
382 /// input.
383 ///
384 /// This may require conversion of inputs in the generated post-tessellation
385 /// vertex shader, but allows the use of nested arrays.
386 #[option(SPVC_COMPILER_OPTION_MSL_RAW_BUFFER_TESE_INPUT, false)]
387 pub raw_buffer_tese_input: bool,
388
389 /// If set, gl_HelperInvocation will be set manually whenever a fragment is discarded.
390 /// Some Metal devices have a bug where `simd_is_helper_thread()` does not return true
391 /// after a fragment has been discarded.
392 ///
393 /// This is a workaround that is only expected to be needed
394 /// until the bug is fixed in Metal; it is provided as an option to allow disabling it when that occurs.
395 #[option(SPVC_COMPILER_OPTION_MSL_MANUAL_HELPER_INVOCATION_UPDATES, true)]
396 pub manual_helper_invocation_updates: bool,
397
398 /// If set, extra checks will be emitted in fragment shaders to prevent writes
399 /// from discarded fragments. Some Metal devices have a bug where writes to storage resources
400 /// from discarded fragment threads continue to occur, despite the fragment being
401 /// discarded.
402 ///
403 /// This is a workaround that is only expected to be needed until the
404 /// bug is fixed in Metal; it is provided as an option so it can be enabled
405 /// only when the bug is present.
406 #[option(SPVC_COMPILER_OPTION_MSL_CHECK_DISCARDED_FRAG_STORES, false)]
407 pub check_discarded_frag_stores: bool,
408
409 /// If set, Lod operands to OpImageSample*DrefExplicitLod for 1D and 2D array images
410 /// will be implemented using a gradient instead of passing the level operand directly.
411 ///
412 /// Some Metal devices have a bug where the `level()` argument to `depth2d_array<T>::sample_compare()`
413 /// in a fragment shader is biased by some unknown amount, possibly dependent on the
414 /// partial derivatives of the texture coordinates.
415 ///
416 /// This is a workaround that is only
417 /// expected to be needed until the bug is fixed in Metal; it is provided as an option
418 /// so it can be enabled only when the bug is present.
419 #[option(SPVC_COMPILER_OPTION_MSL_SAMPLE_DREF_LOD_ARRAY_AS_GRAD, false)]
420 pub sample_dref_lod_array_as_grad: bool,
421
422 /// MSL doesn't guarantee coherence between writes and subsequent reads of read_write textures.
423 /// This inserts fences before each read of a read_write texture to ensure coherency.
424 /// If you're sure you never rely on this, you can set this to false for a possible performance improvement.
425 /// Note: Only Apple's GPU compiler takes advantage of the lack of coherency, so make sure to test on Apple GPUs if you disable this.
426 #[option(SPVC_COMPILER_OPTION_MSL_READWRITE_TEXTURE_FENCES, true)]
427 pub readwrite_texture_fences: bool,
428
429 /// Metal 3.1 introduced a Metal regression bug which causes infinite recursion during
430 /// Metal's analysis of an entry point input structure that is itself recursive. Enabling
431 /// this option will replace the recursive input declaration with a alternate variable of
432 /// type void*, and then cast to the correct type at the top of the entry point function.
433 /// The bug has been reported to Apple, and will hopefully be fixed in future releases.
434 #[option(SPVC_COMPILER_OPTION_MSL_REPLACE_RECURSIVE_INPUTS, false)]
435 pub replace_recursive_inputs: bool,
436
437 /// If set, manual fixups of gradient vectors for cube texture lookups will be performed.
438 /// All released Apple Silicon GPUs to date behave incorrectly when sampling a cube texture
439 /// with explicit gradients. They will ignore one of the three partial derivatives based
440 /// on the selected major axis, and expect the remaining derivatives to be partially
441 /// transformed.
442 #[option(SPVC_COMPILER_OPTION_MSL_AGX_MANUAL_CUBE_GRAD_FIXUP, false)]
443 pub agx_manual_cube_grad_fixup: bool,
444
445 /// Metal will discard fragments with side effects under certain circumstances prematurely.
446 /// Example: CTS test dEQP-VK.fragment_operations.early_fragment.discard_no_early_fragment_tests_depth
447 /// Test will render a full screen quad with varying depth `[0,1]` for each fragment.
448 /// Each fragment will do an operation with side effects, modify the depth value and
449 /// discard the fragment. The test expects the fragment to be run due to:
450 /// <https://registry.khronos.org/vulkan/specs/1.0-extensions/html/vkspec.html#fragops-shader-depthreplacement>
451 /// which states that the fragment shader must be run due to replacing the depth in shader.
452 ///
453 /// However, Metal may prematurely discards fragments without executing them
454 /// (I believe this to be due to a greedy optimization on their end) making the test fail.
455 ///
456 /// This option enforces fragment execution for such cases where the fragment has operations
457 /// with side effects. Provided as an option hoping Metal will fix this issue in the future.
458 #[option(
459 SPVC_COMPILER_OPTION_MSL_FORCE_FRAGMENT_WITH_SIDE_EFFECTS_EXECUTION,
460 false
461 )]
462 pub force_fragment_with_side_effects_execution: bool,
463
464 /// Disables rasterization if BuiltInPosition is not written.
465 #[option(SPVC_COMPILER_OPTION_MSL_AUTO_DISABLE_RASTERIZATION, false)]
466 pub auto_disable_rasterization: bool,
467
468 /// Applies a default value if BuiltInPointSize is not written.
469 #[option(SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_DEFAULT, false)]
470 pub enable_point_size_default: bool,
471}
472
473/// The version of Metal Shading Language to compile to.
474///
475/// Defaults to MSL 1.2.
476#[derive(Copy, Clone, Eq, PartialEq)]
477pub struct MslVersion {
478 /// The major version of MSL.
479 pub major: u32,
480 /// The minor version of MSL.
481 pub minor: u32,
482 /// The patch version of MSL.
483 pub patch: u32,
484}
485
486impl MslVersion {
487 /// Create a new `MslVersion`.
488 pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
489 Self {
490 major,
491 minor,
492 patch,
493 }
494 }
495}
496
497impl Default for MslVersion {
498 fn default() -> Self {
499 MslVersion::from((1, 2))
500 }
501}
502
503impl Debug for MslVersion {
504 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
505 write!(
506 f,
507 "MslVersion({}.{}.{})",
508 self.major, self.minor, self.patch
509 )
510 }
511}
512
513impl From<MslVersion> for u32 {
514 fn from(value: MslVersion) -> Self {
515 (value.major * 10000) + (value.minor * 100) + value.patch
516 }
517}
518
519impl From<(u32, u32)> for MslVersion {
520 fn from(value: (u32, u32)) -> Self {
521 Self {
522 major: value.0,
523 minor: value.1,
524 patch: 0,
525 }
526 }
527}
528
529impl From<(u32, u32, u32)> for MslVersion {
530 fn from(value: (u32, u32, u32)) -> Self {
531 Self {
532 major: value.0,
533 minor: value.1,
534 patch: value.2,
535 }
536 }
537}
538
539/// When using Metal argument buffers, indicates the Metal argument buffer tier level supported by the Metal platform.
540///
541/// Tier capabilities based on recommendations from Apple engineering.
542#[repr(u32)]
543#[derive(Debug, Copy, Clone)]
544pub enum ArgumentBuffersTier {
545 /// Tier1 supports writable images on macOS, but not on iOS.
546 Tier1 = 0,
547 /// Tier2 supports writable images on macOS and iOS, and higher resource count limits.
548 Tier2 = 1,
549}
550
551/// The platform that the Metal runtime will be on.
552#[repr(u32)]
553#[derive(Debug, Copy, Clone)]
554pub enum MetalPlatform {
555 #[allow(non_camel_case_types)]
556 /// iOS (mobile and iPad)
557 iOS = 0,
558 /// macOS (Desktop)
559 MacOS = 1,
560}
561
562/// The type of index in the index buffer.
563#[repr(u32)]
564#[derive(Debug, Copy, Clone)]
565pub enum IndexType {
566 /// No index
567 None = 0,
568 /// Uint16 indices.
569 Uint16 = 1,
570 /// Uint32 indices.
571 Uint32 = 2,
572}
573
574impl From<MetalPlatform> for u32 {
575 fn from(value: MetalPlatform) -> Self {
576 match value {
577 MetalPlatform::iOS => 0,
578 MetalPlatform::MacOS => 1,
579 }
580 }
581}
582
583impl From<IndexType> for u32 {
584 fn from(value: IndexType) -> Self {
585 match value {
586 IndexType::None => 0,
587 IndexType::Uint16 => 1,
588 IndexType::Uint32 => 1,
589 }
590 }
591}
592
593impl From<ArgumentBuffersTier> for u32 {
594 fn from(value: ArgumentBuffersTier) -> Self {
595 match value {
596 ArgumentBuffersTier::Tier1 => 0,
597 ArgumentBuffersTier::Tier2 => 1,
598 }
599 }
600}
601
602/// Buffers that need to be provided to the MSL shader.
603#[non_exhaustive]
604#[derive(Debug, Clone)]
605pub struct BufferRequirements {
606 /// Whether an auxiliary swizzle buffer is needed by the shader.
607 pub needs_swizzle_buffer: bool,
608 /// Whether a buffer containing `STORAGE_BUFFER` buffer sizes to support OpArrayLength
609 /// is needed by the shader.
610 pub needs_buffer_size_buffer: bool,
611 /// Whether an output buffer is needed by the shader.
612 pub needs_output_buffer: bool,
613 /// Whether a patch output buffer is needed by the shader.
614 pub needs_patch_output_buffer: bool,
615 /// Whether an input threadgroup buffer is needed by the shader.
616 pub needs_input_threadgroup_buffer: bool,
617}
618
619/// Pipeline binding information for a resource.
620///
621/// Used to map a SPIR-V resource to an MSL buffer.
622#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
623pub enum ResourceBinding {
624 /// A resource with a qualified layout.
625 ///
626 /// i.e. `layout(set = 0, binding = 1)` in GLSL.
627 Qualified {
628 /// The descriptor set of the qualified layout.
629 set: u32,
630 /// The binding number of the qualified layout.
631 binding: u32,
632 },
633 /// The push constant buffer.
634 PushConstantBuffer,
635 /// The swizzle buffer, at the given index.
636 SwizzleBuffer(u32),
637 /// The buffer binding for buffer size
638 /// buffers to support `OpArrayLength`.
639 BufferSizeBuffer(u32),
640 /// The argument buffer, at the given index.
641 ///
642 /// This buffer binding should be kept as small as possible as all automatic bindings for buffers
643 /// will start at `max(ResourceBinding::ArgumentBuffer) + 1`.
644 ArgumentBuffer(u32),
645}
646
647impl ResourceBinding {
648 /// Create a resource binding for a qualified SPIR-V layout
649 /// specifier.
650 pub const fn from_qualified(set: u32, binding: u32) -> Self {
651 ResourceBinding::Qualified { set, binding }
652 }
653
654 const fn descriptor_set(&self) -> u32 {
655 const PUSH_CONSTANT_DESCRIPTOR_SET: u32 = !0;
656 match self {
657 ResourceBinding::Qualified { set, .. }
658 | ResourceBinding::SwizzleBuffer(set)
659 | ResourceBinding::BufferSizeBuffer(set)
660 | ResourceBinding::ArgumentBuffer(set) => *set,
661 ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_DESCRIPTOR_SET,
662 }
663 }
664
665 const fn binding(&self) -> u32 {
666 const PUSH_CONSTANT_BINDING: u32 = 0;
667 const SWIZZLE_BUFFER_BINDING: u32 = !1;
668 const BUFFER_SIZE_BUFFER_BINDING: u32 = !2;
669 const ARGUMENT_BUFFER_BINDING: u32 = !3;
670
671 match self {
672 ResourceBinding::Qualified { binding, .. } => *binding,
673 ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_BINDING,
674 ResourceBinding::SwizzleBuffer(_) => SWIZZLE_BUFFER_BINDING,
675 ResourceBinding::BufferSizeBuffer(_) => BUFFER_SIZE_BUFFER_BINDING,
676 ResourceBinding::ArgumentBuffer(_) => ARGUMENT_BUFFER_BINDING,
677 }
678 }
679}
680
681/// The MSL target to bind a resource to.
682///
683/// A single SPIR-V binding may bind to multiple
684/// registers for multiple resource types.
685///
686/// The count field indicates the number of resources consumed by this binding, if the binding
687/// represents an array of resources.
688///
689/// If the resource array is a run-time-sized array, which are legal in GLSL or SPIR-V, this value
690/// will be used to declare the array size in MSL, which does not support run-time-sized arrays.
691///
692/// If using MSL 2.0 argument buffers (for iOS only) the resource is not a storage image,
693/// the binding reference we remap to will become an `[[id(N)]]` attribute within
694/// the argument buffer index specified in
695/// [`ResourceBinding::ArgumentBuffer`].
696///
697/// For resources which are bound in the "classic" MSL 1.0 way or discrete descriptors, the remap will
698/// become a `[[buffer(N)]]`, `[[texture(N)]]` or `[[sampler(N)]]` depending on the resource types used.
699#[derive(Debug, Clone, PartialEq, Eq, Hash)]
700pub struct BindTarget {
701 /// The buffer index to bind to, if applicable.
702 pub buffer: u32,
703 /// The texture index to bind to, if applicable.
704 pub texture: u32,
705 /// The sampler index to bind to, if applicable.
706 pub sampler: u32,
707 /// The number of resources consumed by this binding,
708 /// if the binding is an array of resources.
709 pub count: Option<NonZeroU32>,
710}
711
712/// Defines MSL characteristics of a shader interface variable.
713#[derive(Debug, Clone, PartialEq, Eq, Hash)]
714pub struct ShaderInterfaceVariable {
715 /// The builtin for the variable, if any.
716 pub builtin: Option<spirv::BuiltIn>,
717 /// The `vecsize` for this variable, if applicable.
718 ///
719 /// If `vecsize` is Some, it must be greater than or equal to the `vecsize` declared in the shader,
720 /// or behavior in the generated shader is undefined.
721 pub vecsize: Option<NonZeroU32>,
722 /// The format of a shader interface variable.
723 pub format: ShaderVariableFormat,
724 /// Indicates the rate at which a variable changes value.
725 pub rate: ShaderVariableRate,
726}
727
728impl ShaderInterfaceVariable {
729 /// We need to be maybeuninit, because None builtin is represented by i32::MAX,
730 /// which is invalid in Rust. I don't want to expose it just for this, so we'll just
731 /// do some magic.
732 #[must_use]
733 fn to_raw(&self, location: u32) -> MslShaderInterfaceVar2 {
734 let mut base = MslShaderInterfaceVar2 {
735 location,
736 format: self.format,
737 builtin: SpvBuiltIn::Position,
738 vecsize: self.vecsize.map_or(0, NonZeroU32::get),
739 rate: self.rate,
740 };
741
742 if let Some(builtin) = self.builtin {
743 // happy path, we can just set the builtin.
744 base.builtin = SpvBuiltIn(builtin as u32 as i32);
745 } else {
746 base.builtin = SpvBuiltIn(i32::MAX);
747 }
748
749 base
750 }
751}
752
753/// MSL specific APIs.
754impl Compiler<Msl> {
755 /// Get whether the vertex shader requires rasterization to be disabled.
756 pub fn is_rasterization_disabled(&self) -> bool {
757 unsafe { sys::spvc_compiler_msl_is_rasterization_disabled(self.ptr.as_ptr()) }
758 }
759
760 /// Get information such as required buffers for the MSL shader
761 pub fn buffer_requirements(&self) -> BufferRequirements {
762 unsafe {
763 let needs_swizzle_buffer =
764 sys::spvc_compiler_msl_needs_swizzle_buffer(self.ptr.as_ptr());
765 let needs_buffer_size_buffer =
766 sys::spvc_compiler_msl_needs_buffer_size_buffer(self.ptr.as_ptr());
767 let needs_output_buffer = sys::spvc_compiler_msl_needs_output_buffer(self.ptr.as_ptr());
768 let needs_patch_output_buffer =
769 sys::spvc_compiler_msl_needs_patch_output_buffer(self.ptr.as_ptr());
770 let needs_input_threadgroup_buffer =
771 sys::spvc_compiler_msl_needs_input_threadgroup_mem(self.ptr.as_ptr());
772
773 BufferRequirements {
774 needs_swizzle_buffer,
775 needs_buffer_size_buffer,
776 needs_output_buffer,
777 needs_patch_output_buffer,
778 needs_input_threadgroup_buffer,
779 }
780 }
781 }
782
783 /// Add a shader interface variable description used to fix up shader input variables.
784 ///
785 /// If shader inputs are provided, [`CompiledArtifact::is_shader_input_used`] will return true after
786 /// calling [`Compiler::compile`] if the location were used by the MSL code.
787 ///
788 /// Note: this covers the functionality implemented by the SPIR-V Cross
789 /// C API `spvc_compiler_msl_add_vertex_attribute`.
790 pub fn add_shader_input(
791 &mut self,
792 location: u32,
793 variable: &ShaderInterfaceVariable,
794 ) -> error::Result<()> {
795 let variable = variable.to_raw(location);
796 unsafe {
797 sys::spvc_compiler_msl_add_shader_input_2(self.ptr.as_ptr(), &variable).ok(&*self)
798 }
799 }
800
801 /// Add a shader interface variable description used to fix up shader output variables.
802 ///
803 /// If shader outputs are provided, [`CompiledArtifact::is_shader_input_used`] will return true after
804 /// calling [`Compiler::compile`] if the location were used by the MSL code.
805 ///
806 /// Note: this covers the functionality implemented by the SPIR-V Cross
807 /// C API `spvc_compiler_msl_add_vertex_attribute`.
808 pub fn add_shader_output(
809 &mut self,
810 location: u32,
811 variable: &ShaderInterfaceVariable,
812 ) -> error::Result<()> {
813 let variable = variable.to_raw(location);
814 unsafe {
815 sys::spvc_compiler_msl_add_shader_output_2(self.ptr.as_ptr(), &variable).ok(&*self)
816 }
817 }
818
819 /// Add a resource binding to indicate the MSL buffer, texture or sampler index to use for a
820 /// particular resource.
821 ///
822 /// If resource bindings are provided,
823 /// [`CompiledArtifact<Msl>::is_resource_used`] will return true after [`Compiler::compile`] if
824 /// the set/binding combination was used by the MSL code.
825 pub fn add_resource_binding(
826 &mut self,
827 stage: spirv::ExecutionModel,
828 binding: ResourceBinding,
829 bind_target: &BindTarget,
830 ) -> error::Result<()> {
831 let binding = MslResourceBinding2 {
832 stage: SpvExecutionModel(stage as u32 as i32),
833 desc_set: binding.descriptor_set(),
834 binding: binding.binding(),
835 count: bind_target.count.map_or(0, NonZeroU32::get),
836 msl_buffer: bind_target.buffer,
837 msl_texture: bind_target.texture,
838 msl_sampler: bind_target.sampler,
839 };
840 unsafe {
841 sys::spvc_compiler_msl_add_resource_binding_2(self.ptr.as_ptr(), &binding).ok(&*self)
842 }
843 }
844
845 /// When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets.
846 /// This corresponds to VK_KHR_push_descriptor in Vulkan.
847 pub fn add_discrete_descriptor_set(&mut self, desc_set: u32) -> error::Result<()> {
848 unsafe {
849 sys::spvc_compiler_msl_add_discrete_descriptor_set(self.ptr.as_ptr(), desc_set)
850 .ok(&*self)
851 }
852 }
853
854 /// This function marks a resource as using a dynamic offset
855 /// (`VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC` or `VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC`).
856 ///
857 /// `desc_set` and `binding` are the SPIR-V descriptor set and binding of a buffer resource
858 /// in this shader.
859 ///
860 /// `index` is the index within the dynamic offset buffer to use.
861 ///
862 /// This function only has any effect if argument buffers are enabled.
863 /// If so, the buffer will have its address adjusted at the beginning of the shader with
864 /// an offset taken from the dynamic offset buffer.
865 pub fn add_dynamic_buffer(
866 &mut self,
867 desc_set: u32,
868 binding: u32,
869 index: u32,
870 ) -> error::Result<()> {
871 unsafe {
872 sys::spvc_compiler_msl_add_dynamic_buffer(self.ptr.as_ptr(), desc_set, binding, index)
873 .ok(&*self)
874 }
875 }
876
877 /// This function marks a resource an inline uniform block
878 /// (`VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT`)
879 ///
880 /// `desc_set` and `binding` are the SPIR-V descriptor set and binding of a buffer resource
881 /// in this shader.
882 ///
883 /// This function only has any effect if argument buffers are enabled.
884 /// If so, the buffer block will be directly embedded into the argument
885 /// buffer, instead of being referenced indirectly via pointer.
886 pub fn add_inline_uniform_block(&mut self, desc_set: u32, binding: u32) -> error::Result<()> {
887 unsafe {
888 sys::spvc_compiler_msl_add_inline_uniform_block(self.ptr.as_ptr(), desc_set, binding)
889 .ok(&*self)
890 }
891 }
892
893 /// If an argument buffer is large enough, it may need to be in the device storage space rather than
894 /// constant. Opt-in to this behavior here on a per-set basis.
895 pub fn set_argument_buffer_device_address_space(
896 &mut self,
897 desc_set: u32,
898 device_address: bool,
899 ) -> error::Result<()> {
900 unsafe {
901 sys::spvc_compiler_msl_set_argument_buffer_device_address_space(
902 self.ptr.as_ptr(),
903 desc_set,
904 device_address,
905 )
906 .ok(&*self)
907 }
908 }
909
910 /// Remap a sampler with ID to a constexpr sampler.
911 /// Older iOS targets must use constexpr samplers in certain cases (PCF),
912 /// so a static sampler must be used.
913 ///
914 /// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
915 /// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
916 /// The remapped sampler must not be an array of samplers.
917 ///
918 /// Prefer [`Compiler<Msl>::remap_constexpr_sampler_by_binding`] unless you're also doing reflection anyways.
919 pub fn remap_constexpr_sampler(
920 &mut self,
921 variable: impl Into<Handle<VariableId>>,
922 sampler: &ConstexprSampler,
923 ycbcr: Option<&SamplerYcbcrConversion>,
924 ) -> error::Result<()> {
925 let variable = variable.into();
926 let id = self.yield_id(variable)?;
927 if let Some(ycbcr) = ycbcr {
928 unsafe {
929 sys::spvc_compiler_msl_remap_constexpr_sampler_ycbcr(
930 self.ptr.as_ptr(),
931 id,
932 sampler,
933 ycbcr,
934 )
935 .ok(&*self)
936 }
937 } else {
938 unsafe {
939 sys::spvc_compiler_msl_remap_constexpr_sampler(self.ptr.as_ptr(), id, sampler)
940 .ok(&*self)
941 }
942 }
943 }
944
945 /// Remap a sampler with set/binding, to a constexpr sampler.
946 /// Older iOS targets must use constexpr samplers in certain cases (PCF),
947 /// so a static sampler must be used.
948 ///
949 /// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
950 /// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
951 /// The remapped sampler must not be an array of samplers.
952 ///
953 /// Remaps based on ID take priority over set/binding remaps.
954 pub fn remap_constexpr_sampler_by_binding(
955 &mut self,
956 desc_set: u32,
957 binding: u32,
958 sampler: &ConstexprSampler,
959 ycbcr: Option<&SamplerYcbcrConversion>,
960 ) -> error::Result<()> {
961 if let Some(ycbcr) = ycbcr {
962 unsafe {
963 sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(
964 self.ptr.as_ptr(),
965 desc_set,
966 binding,
967 sampler,
968 ycbcr,
969 )
970 .ok(&*self)
971 }
972 } else {
973 unsafe {
974 sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding(
975 self.ptr.as_ptr(),
976 desc_set,
977 binding,
978 sampler,
979 )
980 .ok(&*self)
981 }
982 }
983 }
984
985 /// If using [`CompilerOptions::pad_fragment_output_components`], override the number of components we expect
986 /// to use for a particular location. The default is 4 if number of components is not overridden.
987 pub fn set_fragment_output_components(
988 &mut self,
989 location: u32,
990 components: u32,
991 ) -> error::Result<()> {
992 unsafe {
993 sys::spvc_compiler_msl_set_fragment_output_components(
994 self.ptr.as_ptr(),
995 location,
996 components,
997 )
998 .ok(&*self)
999 }
1000 }
1001
1002 /// Set the suffix for combined image samplers.
1003 pub fn set_combined_sampler_suffix<'str>(
1004 &mut self,
1005 str: impl Into<CompilerStr<'str>>,
1006 ) -> error::Result<()> {
1007 unsafe {
1008 let str = str.into();
1009
1010 let suffix = str.into_cstring_ptr()?;
1011
1012 sys::spvc_compiler_msl_set_combined_sampler_suffix(self.ptr.as_ptr(), suffix.as_ptr())
1013 .ok(&*self)
1014 }
1015 }
1016
1017 /// Get the suffix for combined image samplers.
1018 pub fn combined_sampler_suffix(&self) -> CompilerStr<'_> {
1019 unsafe {
1020 let suffix = sys::spvc_compiler_msl_get_combined_sampler_suffix(self.ptr.as_ptr());
1021 CompilerStr::from_ptr(suffix, self.ctx.drop_guard())
1022 }
1023 }
1024
1025 /// Mask a stage output by location.
1026 ///
1027 /// If a shader output is active in this stage, but inactive in a subsequent stage,
1028 /// this can be signalled here. This can be used to work around certain cross-stage matching problems
1029 /// which plagues MSL in certain scenarios.
1030 ///
1031 /// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private
1032 /// variable.
1033 ///
1034 /// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly.
1035 ///
1036 pub fn mask_stage_output_by_location(
1037 &mut self,
1038 location: u32,
1039 component: u32,
1040 ) -> crate::error::Result<()> {
1041 unsafe {
1042 sys::spvc_compiler_mask_stage_output_by_location(self.ptr.as_ptr(), location, component)
1043 .ok(&*self)
1044 }
1045 }
1046
1047 /// Mask a stage output by builtin. Masking builtins only takes effect if the builtin in question is part of the stage output interface.
1048 ///
1049 /// If a shader output is active in this stage, but inactive in a subsequent stage,
1050 /// this can be signalled here. This can be used to work around certain cross-stage matching problems
1051 /// which plagues MSL in certain scenarios.
1052 ///
1053 /// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private
1054 /// variable.
1055 ///
1056 /// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly.
1057 /// Masking builtins only takes effect if the builtin in question is part of the stage output interface.
1058 pub fn mask_stage_output_by_builtin(
1059 &mut self,
1060 builtin: spirv::BuiltIn,
1061 ) -> crate::error::Result<()> {
1062 unsafe {
1063 sys::spvc_compiler_mask_stage_output_by_builtin(
1064 self.ptr.as_ptr(),
1065 SpvBuiltIn(builtin as u32 as i32),
1066 )
1067 .ok(&*self)
1068 }
1069 }
1070}
1071
1072#[derive(Copy, Clone, Debug, Default)]
1073#[non_exhaustive]
1074/// The tier of automatic resource binding.
1075///
1076/// Note that tertiary and quaternary bindings are not accessible via
1077/// the SPIR-V Cross C API.
1078pub enum AutomaticResourceBindingTier {
1079 #[default]
1080 /// The primary automatic resource binding.
1081 Primary,
1082
1083 /// Should only be used for combined image samplers, in which case the
1084 /// sampler's binding is returned instead.
1085 ///
1086 /// Also used for the auxillary image atomic buffer.
1087 Secondary,
1088}
1089
1090impl CompiledArtifact<Msl> {
1091 /// Returns whether the set/binding combination provided in [`Compiler<Msl>::add_resource_binding`]
1092 /// was used.
1093 pub fn is_resource_used(&self, model: spirv::ExecutionModel, binding: ResourceBinding) -> bool {
1094 unsafe {
1095 sys::spvc_compiler_msl_is_resource_used(
1096 self.compiler.ptr.as_ptr(),
1097 SpvExecutionModel(model as u32 as i32),
1098 binding.descriptor_set(),
1099 binding.binding(),
1100 )
1101 }
1102 }
1103
1104 /// Returns whether the location provided in [`Compiler<Msl>::add_shader_input`]
1105 /// was used.
1106 pub fn is_shader_input_used(&self, location: u32) -> bool {
1107 unsafe { sys::spvc_compiler_msl_is_shader_input_used(self.compiler.ptr.as_ptr(), location) }
1108 }
1109
1110 /// Returns whether the location provided in [`Compiler<Msl>::add_shader_output`]
1111 /// was used.
1112 pub fn is_shader_output_used(&self, location: u32) -> bool {
1113 unsafe {
1114 sys::spvc_compiler_msl_is_shader_output_used(self.compiler.ptr.as_ptr(), location)
1115 }
1116 }
1117
1118 /// For a variable resource ID, report the automatically assigned resource index.
1119 ///
1120 /// If the descriptor set was part of an argument buffer, report the `[[id(N)]]`,
1121 /// or `[[buffer/texture/sampler]]` binding for other resources.
1122 ///
1123 /// If the resource was a combined image sampler, report the image binding for [`AutomaticResourceBindingTier::Primary`],
1124 /// or the sampler half for [`AutomaticResourceBindingTier::Secondary`].
1125 ///
1126 /// If no binding exists, None is returned.
1127 pub fn automatic_resource_binding(
1128 &self,
1129 handle: impl Into<Handle<VariableId>>,
1130 tier: AutomaticResourceBindingTier,
1131 ) -> error::Result<Option<u32>> {
1132 let handle = handle.into();
1133 let id = self.yield_id(handle)?;
1134
1135 let res = match tier {
1136 AutomaticResourceBindingTier::Primary => unsafe {
1137 sys::spvc_compiler_msl_get_automatic_resource_binding(self.ptr.as_ptr(), id)
1138 },
1139 AutomaticResourceBindingTier::Secondary => unsafe {
1140 sys::spvc_compiler_msl_get_automatic_resource_binding_secondary(
1141 self.ptr.as_ptr(),
1142 id,
1143 )
1144 },
1145 };
1146
1147 if res == u32::MAX {
1148 Ok(None)
1149 } else {
1150 Ok(Some(res))
1151 }
1152 }
1153
1154 /// Query if a variable ID was used as a depth resource.
1155 ///
1156 /// This is meaningful for MSL since descriptor types depend on this knowledge.
1157 /// Cases which return true:
1158 /// - Images which are declared with depth = 1 image type.
1159 /// - Samplers which are statically used at least once with Dref opcodes.
1160 /// - Images which are statically used at least once with Dref opcodes.
1161 pub fn variable_is_depth_or_compare(
1162 &self,
1163 variable: impl Into<Handle<VariableId>>,
1164 ) -> error::Result<bool> {
1165 let variable = variable.into();
1166 let id = self.yield_id(variable)?;
1167 unsafe {
1168 Ok(sys::spvc_compiler_variable_is_depth_or_compare(
1169 self.ptr.as_ptr(),
1170 id,
1171 ))
1172 }
1173 }
1174}
1175
1176#[cfg(test)]
1177mod test {
1178 use crate::compile::msl::CompilerOptions;
1179 use spirv_cross_sys::spvc_compiler_create_compiler_options;
1180
1181 use crate::compile::sealed::ApplyCompilerOptions;
1182 use crate::error::{SpirvCrossError, ToContextError};
1183 use crate::Compiler;
1184 use crate::{targets, Module};
1185
1186 static BASIC_SPV: &[u8] = include_bytes!("../../../basic.spv");
1187
1188 #[test]
1189 pub fn msl_opts() -> Result<(), SpirvCrossError> {
1190 let words = Vec::from(BASIC_SPV);
1191 let words = Module::from_words(bytemuck::cast_slice(&words));
1192
1193 let compiler: Compiler<targets::Msl> = Compiler::new(words)?;
1194 let resources = compiler.shader_resources()?.all_resources()?;
1195
1196 let mut opts_ptr = std::ptr::null_mut();
1197
1198 unsafe {
1199 spvc_compiler_create_compiler_options(compiler.ptr.as_ptr(), &mut opts_ptr)
1200 .ok(&compiler)?;
1201 }
1202
1203 // println!("{:#?}", resources);
1204 let opts = CompilerOptions::default();
1205 unsafe {
1206 opts.apply(opts_ptr, &compiler)?;
1207 }
1208
1209 // match ty.inner {
1210 // TypeInner::Struct(ty) => {
1211 // compiler.get_type(ty.members[0].id)?;
1212 // }
1213 // TypeInner::Vector { .. } => {}
1214 // _ => {}
1215 // }
1216 Ok(())
1217 }
1218}