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 /// Disablle 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 ///
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
465/// The version of Metal Shading Language to compile to.
466///
467/// Defaults to MSL 1.2.
468#[derive(Copy, Clone, Eq, PartialEq)]
469pub struct MslVersion {
470 /// The major version of MSL.
471 pub major: u32,
472 /// The minor version of MSL.
473 pub minor: u32,
474 /// The patch version of MSL.
475 pub patch: u32,
476}
477
478impl MslVersion {
479 /// Create a new `MslVersion`.
480 pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
481 Self {
482 major,
483 minor,
484 patch,
485 }
486 }
487}
488
489impl Default for MslVersion {
490 fn default() -> Self {
491 MslVersion::from((1, 2))
492 }
493}
494
495impl Debug for MslVersion {
496 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
497 write!(
498 f,
499 "MslVersion({}.{}.{})",
500 self.major, self.minor, self.patch
501 )
502 }
503}
504
505impl From<MslVersion> for u32 {
506 fn from(value: MslVersion) -> Self {
507 (value.major * 10000) + (value.minor * 100) + value.patch
508 }
509}
510
511impl From<(u32, u32)> for MslVersion {
512 fn from(value: (u32, u32)) -> Self {
513 Self {
514 major: value.0,
515 minor: value.1,
516 patch: 0,
517 }
518 }
519}
520
521impl From<(u32, u32, u32)> for MslVersion {
522 fn from(value: (u32, u32, u32)) -> Self {
523 Self {
524 major: value.0,
525 minor: value.1,
526 patch: value.2,
527 }
528 }
529}
530
531/// When using Metal argument buffers, indicates the Metal argument buffer tier level supported by the Metal platform.
532///
533/// Tier capabilities based on recommendations from Apple engineering.
534#[repr(u32)]
535#[derive(Debug, Copy, Clone)]
536pub enum ArgumentBuffersTier {
537 /// Tier1 supports writable images on macOS, but not on iOS.
538 Tier1 = 0,
539 /// Tier2 supports writable images on macOS and iOS, and higher resource count limits.
540 Tier2 = 1,
541}
542
543/// The platform that the Metal runtime will be on.
544#[repr(u32)]
545#[derive(Debug, Copy, Clone)]
546pub enum MetalPlatform {
547 #[allow(non_camel_case_types)]
548 /// iOS (mobile and iPad)
549 iOS = 0,
550 /// macOS (Desktop)
551 MacOS = 1,
552}
553
554/// The type of index in the index buffer.
555#[repr(u32)]
556#[derive(Debug, Copy, Clone)]
557pub enum IndexType {
558 /// No index
559 None = 0,
560 /// Uint16 indices.
561 Uint16 = 1,
562 /// Uint32 indices.
563 Uint32 = 2,
564}
565
566impl From<MetalPlatform> for u32 {
567 fn from(value: MetalPlatform) -> Self {
568 match value {
569 MetalPlatform::iOS => 0,
570 MetalPlatform::MacOS => 1,
571 }
572 }
573}
574
575impl From<IndexType> for u32 {
576 fn from(value: IndexType) -> Self {
577 match value {
578 IndexType::None => 0,
579 IndexType::Uint16 => 1,
580 IndexType::Uint32 => 1,
581 }
582 }
583}
584
585impl From<ArgumentBuffersTier> for u32 {
586 fn from(value: ArgumentBuffersTier) -> Self {
587 match value {
588 ArgumentBuffersTier::Tier1 => 0,
589 ArgumentBuffersTier::Tier2 => 1,
590 }
591 }
592}
593
594/// Buffers that need to be provided to the MSL shader.
595#[non_exhaustive]
596#[derive(Debug, Clone)]
597pub struct BufferRequirements {
598 /// Whether an auxiliary swizzle buffer is needed by the shader.
599 pub needs_swizzle_buffer: bool,
600 /// Whether a buffer containing `STORAGE_BUFFER` buffer sizes to support OpArrayLength
601 /// is needed by the shader.
602 pub needs_buffer_size_buffer: bool,
603 /// Whether an output buffer is needed by the shader.
604 pub needs_output_buffer: bool,
605 /// Whether a patch output buffer is needed by the shader.
606 pub needs_patch_output_buffer: bool,
607 /// Whether an input threadgroup buffer is needed by the shader.
608 pub needs_input_threadgroup_buffer: bool,
609}
610
611/// Pipeline binding information for a resource.
612///
613/// Used to map a SPIR-V resource to an MSL buffer.
614#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
615pub enum ResourceBinding {
616 /// A resource with a qualified layout.
617 ///
618 /// i.e. `layout(set = 0, binding = 1)` in GLSL.
619 Qualified {
620 /// The descriptor set of the qualified layout.
621 set: u32,
622 /// The binding number of the qualified layout.
623 binding: u32,
624 },
625 /// The push constant buffer.
626 PushConstantBuffer,
627 /// The swizzle buffer, at the given index.
628 SwizzleBuffer(u32),
629 /// The buffer binding for buffer size
630 /// buffers to support `OpArrayLength`.
631 BufferSizeBuffer(u32),
632 /// The argument buffer, at the given index.
633 ///
634 /// This buffer binding should be kept as small as possible as all automatic bindings for buffers
635 /// will start at `max(ResourceBinding::ArgumentBuffer) + 1`.
636 ArgumentBuffer(u32),
637}
638
639impl ResourceBinding {
640 /// Create a resource binding for a qualified SPIR-V layout
641 /// specifier.
642 pub const fn from_qualified(set: u32, binding: u32) -> Self {
643 ResourceBinding::Qualified { set, binding }
644 }
645
646 const fn descriptor_set(&self) -> u32 {
647 const PUSH_CONSTANT_DESCRIPTOR_SET: u32 = !0;
648 match self {
649 ResourceBinding::Qualified { set, .. }
650 | ResourceBinding::SwizzleBuffer(set)
651 | ResourceBinding::BufferSizeBuffer(set)
652 | ResourceBinding::ArgumentBuffer(set) => *set,
653 ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_DESCRIPTOR_SET,
654 }
655 }
656
657 const fn binding(&self) -> u32 {
658 const PUSH_CONSTANT_BINDING: u32 = 0;
659 const SWIZZLE_BUFFER_BINDING: u32 = !1;
660 const BUFFER_SIZE_BUFFER_BINDING: u32 = !2;
661 const ARGUMENT_BUFFER_BINDING: u32 = !3;
662
663 match self {
664 ResourceBinding::Qualified { binding, .. } => *binding,
665 ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_BINDING,
666 ResourceBinding::SwizzleBuffer(_) => SWIZZLE_BUFFER_BINDING,
667 ResourceBinding::BufferSizeBuffer(_) => BUFFER_SIZE_BUFFER_BINDING,
668 ResourceBinding::ArgumentBuffer(_) => ARGUMENT_BUFFER_BINDING,
669 }
670 }
671}
672
673/// The MSL target to bind a resource to.
674///
675/// A single SPIR-V binding may bind to multiple
676/// registers for multiple resource types.
677///
678/// The count field indicates the number of resources consumed by this binding, if the binding
679/// represents an array of resources.
680///
681/// If the resource array is a run-time-sized array, which are legal in GLSL or SPIR-V, this value
682/// will be used to declare the array size in MSL, which does not support run-time-sized arrays.
683///
684/// If using MSL 2.0 argument buffers (for iOS only) the resource is not a storage image,
685/// the binding reference we remap to will become an `[[id(N)]]` attribute within
686/// the argument buffer index specified in
687/// [`ResourceBinding::ArgumentBuffer`].
688///
689/// For resources which are bound in the "classic" MSL 1.0 way or discrete descriptors, the remap will
690/// become a `[[buffer(N)]]`, `[[texture(N)]]` or `[[sampler(N)]]` depending on the resource types used.
691#[derive(Debug, Clone, PartialEq, Eq, Hash)]
692pub struct BindTarget {
693 /// The buffer index to bind to, if applicable.
694 pub buffer: u32,
695 /// The texture index to bind to, if applicable.
696 pub texture: u32,
697 /// The sampler index to bind to, if applicable.
698 pub sampler: u32,
699 /// The number of resources consumed by this binding,
700 /// if the binding is an array of resources.
701 pub count: Option<NonZeroU32>,
702}
703
704/// Defines MSL characteristics of a shader interface variable.
705#[derive(Debug, Clone, PartialEq, Eq, Hash)]
706pub struct ShaderInterfaceVariable {
707 /// The builtin for the variable, if any.
708 pub builtin: Option<spirv::BuiltIn>,
709 /// The `vecsize` for this variable, if applicable.
710 ///
711 /// If `vecsize` is Some, it must be greater than or equal to the `vecsize` declared in the shader,
712 /// or behavior in the generated shader is undefined.
713 pub vecsize: Option<NonZeroU32>,
714 /// The format of a shader interface variable.
715 pub format: ShaderVariableFormat,
716 /// Indicates the rate at which a variable changes value.
717 pub rate: ShaderVariableRate,
718}
719
720impl ShaderInterfaceVariable {
721 /// We need to be maybeuninit, because None builtin is represented by i32::MAX,
722 /// which is invalid in Rust. I don't want to expose it just for this, so we'll just
723 /// do some magic.
724 #[must_use]
725 fn to_raw(&self, location: u32) -> MslShaderInterfaceVar2 {
726 let mut base = MslShaderInterfaceVar2 {
727 location,
728 format: self.format,
729 builtin: SpvBuiltIn::Position,
730 vecsize: self.vecsize.map_or(0, NonZeroU32::get),
731 rate: self.rate,
732 };
733
734 if let Some(builtin) = self.builtin {
735 // happy path, we can just set the builtin.
736 base.builtin = SpvBuiltIn(builtin as u32 as i32);
737 } else {
738 base.builtin = SpvBuiltIn(i32::MAX);
739 }
740
741 base
742 }
743}
744
745/// MSL specific APIs.
746impl Compiler<Msl> {
747 /// Get whether the vertex shader requires rasterization to be disabled.
748 pub fn is_rasterization_disabled(&self) -> bool {
749 unsafe { sys::spvc_compiler_msl_is_rasterization_disabled(self.ptr.as_ptr()) }
750 }
751
752 /// Get information such as required buffers for the MSL shader
753 pub fn buffer_requirements(&self) -> BufferRequirements {
754 unsafe {
755 let needs_swizzle_buffer =
756 sys::spvc_compiler_msl_needs_swizzle_buffer(self.ptr.as_ptr());
757 let needs_buffer_size_buffer =
758 sys::spvc_compiler_msl_needs_buffer_size_buffer(self.ptr.as_ptr());
759 let needs_output_buffer = sys::spvc_compiler_msl_needs_output_buffer(self.ptr.as_ptr());
760 let needs_patch_output_buffer =
761 sys::spvc_compiler_msl_needs_patch_output_buffer(self.ptr.as_ptr());
762 let needs_input_threadgroup_buffer =
763 sys::spvc_compiler_msl_needs_input_threadgroup_mem(self.ptr.as_ptr());
764
765 BufferRequirements {
766 needs_swizzle_buffer,
767 needs_buffer_size_buffer,
768 needs_output_buffer,
769 needs_patch_output_buffer,
770 needs_input_threadgroup_buffer,
771 }
772 }
773 }
774
775 /// Add a shader interface variable description used to fix up shader input variables.
776 ///
777 /// If shader inputs are provided, [`CompiledArtifact::is_shader_input_used`] will return true after
778 /// calling [`Compiler::compile`] if the location were used by the MSL code.
779 ///
780 /// Note: this covers the functionality implemented by the SPIR-V Cross
781 /// C API `spvc_compiler_msl_add_vertex_attribute`.
782 pub fn add_shader_input(
783 &mut self,
784 location: u32,
785 variable: &ShaderInterfaceVariable,
786 ) -> error::Result<()> {
787 let variable = variable.to_raw(location);
788 unsafe {
789 sys::spvc_compiler_msl_add_shader_input_2(self.ptr.as_ptr(), &variable).ok(&*self)
790 }
791 }
792
793 /// Add a shader interface variable description used to fix up shader output variables.
794 ///
795 /// If shader outputs are provided, [`CompiledArtifact::is_shader_input_used`] will return true after
796 /// calling [`Compiler::compile`] if the location were used by the MSL code.
797 ///
798 /// Note: this covers the functionality implemented by the SPIR-V Cross
799 /// C API `spvc_compiler_msl_add_vertex_attribute`.
800 pub fn add_shader_output(
801 &mut self,
802 location: u32,
803 variable: &ShaderInterfaceVariable,
804 ) -> error::Result<()> {
805 let variable = variable.to_raw(location);
806 unsafe {
807 sys::spvc_compiler_msl_add_shader_output_2(self.ptr.as_ptr(), &variable).ok(&*self)
808 }
809 }
810
811 /// Add a resource binding to indicate the MSL buffer, texture or sampler index to use for a
812 /// particular resource.
813 ///
814 /// If resource bindings are provided,
815 /// [`CompiledArtifact<Msl>::is_resource_used`] will return true after [`Compiler::compile`] if
816 /// the set/binding combination was used by the MSL code.
817 pub fn add_resource_binding(
818 &mut self,
819 stage: spirv::ExecutionModel,
820 binding: ResourceBinding,
821 bind_target: &BindTarget,
822 ) -> error::Result<()> {
823 let binding = MslResourceBinding2 {
824 stage: SpvExecutionModel(stage as u32 as i32),
825 desc_set: binding.descriptor_set(),
826 binding: binding.binding(),
827 count: bind_target.count.map_or(0, NonZeroU32::get),
828 msl_buffer: bind_target.buffer,
829 msl_texture: bind_target.texture,
830 msl_sampler: bind_target.sampler,
831 };
832 unsafe {
833 sys::spvc_compiler_msl_add_resource_binding_2(self.ptr.as_ptr(), &binding).ok(&*self)
834 }
835 }
836
837 /// When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets.
838 /// This corresponds to VK_KHR_push_descriptor in Vulkan.
839 pub fn add_discrete_descriptor_set(&mut self, desc_set: u32) -> error::Result<()> {
840 unsafe {
841 sys::spvc_compiler_msl_add_discrete_descriptor_set(self.ptr.as_ptr(), desc_set)
842 .ok(&*self)
843 }
844 }
845
846 /// This function marks a resource as using a dynamic offset
847 /// (`VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC` or `VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC`).
848 ///
849 /// `desc_set` and `binding` are the SPIR-V descriptor set and binding of a buffer resource
850 /// in this shader.
851 ///
852 /// `index` is the index within the dynamic offset buffer to use.
853 ///
854 /// This function only has any effect if argument buffers are enabled.
855 /// If so, the buffer will have its address adjusted at the beginning of the shader with
856 /// an offset taken from the dynamic offset buffer.
857 pub fn add_dynamic_buffer(
858 &mut self,
859 desc_set: u32,
860 binding: u32,
861 index: u32,
862 ) -> error::Result<()> {
863 unsafe {
864 sys::spvc_compiler_msl_add_dynamic_buffer(self.ptr.as_ptr(), desc_set, binding, index)
865 .ok(&*self)
866 }
867 }
868
869 /// This function marks a resource an inline uniform block
870 /// (`VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT`)
871 ///
872 /// `desc_set` and `binding` are the SPIR-V descriptor set and binding of a buffer resource
873 /// in this shader.
874 ///
875 /// This function only has any effect if argument buffers are enabled.
876 /// If so, the buffer block will be directly embedded into the argument
877 /// buffer, instead of being referenced indirectly via pointer.
878 pub fn add_inline_uniform_block(&mut self, desc_set: u32, binding: u32) -> error::Result<()> {
879 unsafe {
880 sys::spvc_compiler_msl_add_inline_uniform_block(self.ptr.as_ptr(), desc_set, binding)
881 .ok(&*self)
882 }
883 }
884
885 /// If an argument buffer is large enough, it may need to be in the device storage space rather than
886 /// constant. Opt-in to this behavior here on a per-set basis.
887 pub fn set_argument_buffer_device_address_space(
888 &mut self,
889 desc_set: u32,
890 device_address: bool,
891 ) -> error::Result<()> {
892 unsafe {
893 sys::spvc_compiler_msl_set_argument_buffer_device_address_space(
894 self.ptr.as_ptr(),
895 desc_set,
896 device_address,
897 )
898 .ok(&*self)
899 }
900 }
901
902 /// Remap a sampler with ID to a constexpr sampler.
903 /// Older iOS targets must use constexpr samplers in certain cases (PCF),
904 /// so a static sampler must be used.
905 ///
906 /// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
907 /// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
908 /// The remapped sampler must not be an array of samplers.
909 ///
910 /// Prefer [`Compiler<Msl>::remap_constexpr_sampler_by_binding`] unless you're also doing reflection anyways.
911 pub fn remap_constexpr_sampler(
912 &mut self,
913 variable: impl Into<Handle<VariableId>>,
914 sampler: &ConstexprSampler,
915 ycbcr: Option<&SamplerYcbcrConversion>,
916 ) -> error::Result<()> {
917 let variable = variable.into();
918 let id = self.yield_id(variable)?;
919 if let Some(ycbcr) = ycbcr {
920 unsafe {
921 sys::spvc_compiler_msl_remap_constexpr_sampler_ycbcr(
922 self.ptr.as_ptr(),
923 id,
924 sampler,
925 ycbcr,
926 )
927 .ok(&*self)
928 }
929 } else {
930 unsafe {
931 sys::spvc_compiler_msl_remap_constexpr_sampler(self.ptr.as_ptr(), id, sampler)
932 .ok(&*self)
933 }
934 }
935 }
936
937 /// Remap a sampler with set/binding, to a constexpr sampler.
938 /// Older iOS targets must use constexpr samplers in certain cases (PCF),
939 /// so a static sampler must be used.
940 ///
941 /// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
942 /// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
943 /// The remapped sampler must not be an array of samplers.
944 ///
945 /// Remaps based on ID take priority over set/binding remaps.
946 pub fn remap_constexpr_sampler_by_binding(
947 &mut self,
948 desc_set: u32,
949 binding: u32,
950 sampler: &ConstexprSampler,
951 ycbcr: Option<&SamplerYcbcrConversion>,
952 ) -> error::Result<()> {
953 if let Some(ycbcr) = ycbcr {
954 unsafe {
955 sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(
956 self.ptr.as_ptr(),
957 desc_set,
958 binding,
959 sampler,
960 ycbcr,
961 )
962 .ok(&*self)
963 }
964 } else {
965 unsafe {
966 sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding(
967 self.ptr.as_ptr(),
968 desc_set,
969 binding,
970 sampler,
971 )
972 .ok(&*self)
973 }
974 }
975 }
976
977 /// If using [`CompilerOptions::pad_fragment_output_components`], override the number of components we expect
978 /// to use for a particular location. The default is 4 if number of components is not overridden.
979 pub fn set_fragment_output_components(
980 &mut self,
981 location: u32,
982 components: u32,
983 ) -> error::Result<()> {
984 unsafe {
985 sys::spvc_compiler_msl_set_fragment_output_components(
986 self.ptr.as_ptr(),
987 location,
988 components,
989 )
990 .ok(&*self)
991 }
992 }
993
994 /// Set the suffix for combined image samplers.
995 pub fn set_combined_sampler_suffix<'str>(
996 &mut self,
997 str: impl Into<CompilerStr<'str>>,
998 ) -> error::Result<()> {
999 unsafe {
1000 let str = str.into();
1001
1002 let suffix = str.into_cstring_ptr()?;
1003
1004 sys::spvc_compiler_msl_set_combined_sampler_suffix(self.ptr.as_ptr(), suffix.as_ptr())
1005 .ok(&*self)
1006 }
1007 }
1008
1009 /// Get the suffix for combined image samplers.
1010 pub fn combined_sampler_suffix(&self) -> CompilerStr {
1011 unsafe {
1012 let suffix = sys::spvc_compiler_msl_get_combined_sampler_suffix(self.ptr.as_ptr());
1013 CompilerStr::from_ptr(suffix, self.ctx.drop_guard())
1014 }
1015 }
1016
1017 /// Mask a stage output by location.
1018 ///
1019 /// If a shader output is active in this stage, but inactive in a subsequent stage,
1020 /// this can be signalled here. This can be used to work around certain cross-stage matching problems
1021 /// which plagues MSL in certain scenarios.
1022 ///
1023 /// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private
1024 /// variable.
1025 ///
1026 /// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly.
1027 ///
1028 pub fn mask_stage_output_by_location(
1029 &mut self,
1030 location: u32,
1031 component: u32,
1032 ) -> crate::error::Result<()> {
1033 unsafe {
1034 sys::spvc_compiler_mask_stage_output_by_location(self.ptr.as_ptr(), location, component)
1035 .ok(&*self)
1036 }
1037 }
1038
1039 /// Mask a stage output by builtin. Masking builtins only takes effect if the builtin in question is part of the stage output interface.
1040 ///
1041 /// If a shader output is active in this stage, but inactive in a subsequent stage,
1042 /// this can be signalled here. This can be used to work around certain cross-stage matching problems
1043 /// which plagues MSL in certain scenarios.
1044 ///
1045 /// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private
1046 /// variable.
1047 ///
1048 /// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly.
1049 /// Masking builtins only takes effect if the builtin in question is part of the stage output interface.
1050 pub fn mask_stage_output_by_builtin(
1051 &mut self,
1052 builtin: spirv::BuiltIn,
1053 ) -> crate::error::Result<()> {
1054 unsafe {
1055 sys::spvc_compiler_mask_stage_output_by_builtin(
1056 self.ptr.as_ptr(),
1057 SpvBuiltIn(builtin as u32 as i32),
1058 )
1059 .ok(&*self)
1060 }
1061 }
1062}
1063
1064#[derive(Copy, Clone, Debug, Default)]
1065#[non_exhaustive]
1066/// The tier of automatic resource binding.
1067///
1068/// Note that tertiary and quaternary bindings are not accessible via
1069/// the SPIR-V Cross C API.
1070pub enum AutomaticResourceBindingTier {
1071 #[default]
1072 /// The primary automatic resource binding.
1073 Primary,
1074
1075 /// Should only be used for combined image samplers, in which case the
1076 /// sampler's binding is returned instead.
1077 ///
1078 /// Also used for the auxillary image atomic buffer.
1079 Secondary,
1080}
1081
1082impl CompiledArtifact<Msl> {
1083 /// Returns whether the set/binding combination provided in [`Compiler<Msl>::add_resource_binding`]
1084 /// was used.
1085 pub fn is_resource_used(&self, model: spirv::ExecutionModel, binding: ResourceBinding) -> bool {
1086 unsafe {
1087 sys::spvc_compiler_msl_is_resource_used(
1088 self.compiler.ptr.as_ptr(),
1089 SpvExecutionModel(model as u32 as i32),
1090 binding.descriptor_set(),
1091 binding.binding(),
1092 )
1093 }
1094 }
1095
1096 /// Returns whether the location provided in [`Compiler<Msl>::add_shader_input`]
1097 /// was used.
1098 pub fn is_shader_input_used(&self, location: u32) -> bool {
1099 unsafe { sys::spvc_compiler_msl_is_shader_input_used(self.compiler.ptr.as_ptr(), location) }
1100 }
1101
1102 /// Returns whether the location provided in [`Compiler<Msl>::add_shader_output`]
1103 /// was used.
1104 pub fn is_shader_output_used(&self, location: u32) -> bool {
1105 unsafe {
1106 sys::spvc_compiler_msl_is_shader_output_used(self.compiler.ptr.as_ptr(), location)
1107 }
1108 }
1109
1110 /// For a variable resource ID, report the automatically assigned resource index.
1111 ///
1112 /// If the descriptor set was part of an argument buffer, report the `[[id(N)]]`,
1113 /// or `[[buffer/texture/sampler]]` binding for other resources.
1114 ///
1115 /// If the resource was a combined image sampler, report the image binding for [`AutomaticResourceBindingTier::Primary`],
1116 /// or the sampler half for [`AutomaticResourceBindingTier::Secondary`].
1117 ///
1118 /// If no binding exists, None is returned.
1119 pub fn automatic_resource_binding(
1120 &self,
1121 handle: impl Into<Handle<VariableId>>,
1122 tier: AutomaticResourceBindingTier,
1123 ) -> error::Result<Option<u32>> {
1124 let handle = handle.into();
1125 let id = self.yield_id(handle)?;
1126
1127 let res = match tier {
1128 AutomaticResourceBindingTier::Primary => unsafe {
1129 sys::spvc_compiler_msl_get_automatic_resource_binding(self.ptr.as_ptr(), id)
1130 },
1131 AutomaticResourceBindingTier::Secondary => unsafe {
1132 sys::spvc_compiler_msl_get_automatic_resource_binding_secondary(
1133 self.ptr.as_ptr(),
1134 id,
1135 )
1136 },
1137 };
1138
1139 if res == u32::MAX {
1140 Ok(None)
1141 } else {
1142 Ok(Some(res))
1143 }
1144 }
1145
1146 /// Query if a variable ID was used as a depth resource.
1147 ///
1148 /// This is meaningful for MSL since descriptor types depend on this knowledge.
1149 /// Cases which return true:
1150 /// - Images which are declared with depth = 1 image type.
1151 /// - Samplers which are statically used at least once with Dref opcodes.
1152 /// - Images which are statically used at least once with Dref opcodes.
1153 pub fn variable_is_depth_or_compare(
1154 &self,
1155 variable: impl Into<Handle<VariableId>>,
1156 ) -> error::Result<bool> {
1157 let variable = variable.into();
1158 let id = self.yield_id(variable)?;
1159 unsafe {
1160 Ok(sys::spvc_compiler_variable_is_depth_or_compare(
1161 self.ptr.as_ptr(),
1162 id,
1163 ))
1164 }
1165 }
1166}
1167
1168#[cfg(test)]
1169mod test {
1170 use crate::compile::msl::CompilerOptions;
1171 use spirv_cross_sys::spvc_compiler_create_compiler_options;
1172
1173 use crate::compile::sealed::ApplyCompilerOptions;
1174 use crate::error::{SpirvCrossError, ToContextError};
1175 use crate::Compiler;
1176 use crate::{targets, Module};
1177
1178 static BASIC_SPV: &[u8] = include_bytes!("../../../basic.spv");
1179
1180 #[test]
1181 pub fn msl_opts() -> Result<(), SpirvCrossError> {
1182 let words = Vec::from(BASIC_SPV);
1183 let words = Module::from_words(bytemuck::cast_slice(&words));
1184
1185 let compiler: Compiler<targets::Msl> = Compiler::new(words)?;
1186 let resources = compiler.shader_resources()?.all_resources()?;
1187
1188 let mut opts_ptr = std::ptr::null_mut();
1189
1190 unsafe {
1191 spvc_compiler_create_compiler_options(compiler.ptr.as_ptr(), &mut opts_ptr)
1192 .ok(&compiler)?;
1193 }
1194
1195 // println!("{:#?}", resources);
1196 let opts = CompilerOptions::default();
1197 unsafe {
1198 opts.apply(opts_ptr, &compiler)?;
1199 }
1200
1201 // match ty.inner {
1202 // TypeInner::Struct(ty) => {
1203 // compiler.get_type(ty.members[0].id)?;
1204 // }
1205 // TypeInner::Vector { .. } => {}
1206 // _ => {}
1207 // }
1208 Ok(())
1209 }
1210}