Skip to main content

Crate metal2vulkan

Crate metal2vulkan 

Source
Expand description

metal2vulkan — Metal AIR (LLVM bitcode) -> Vulkan SPIR-V, via a native LLVM-IR emitter.

The decisive difference from the legacy metal2vulkanspirv crate: that one targeted the OpenCL/Kernel SPIR-V backend (spirv64-unknown-unknown), which emits UNSTRUCTURED, Physical64/OpenCL-dialect SPIR-V, then did a ~1300-line regex dialect rewrite + a hand-written structurizer to reach a Vulkan-legal module. Here the native emitter produces OpCapability Shader / Logical GLSL450 SPIR-V directly from sanitized AIR LLVM IR. What remains is the stage interface — done as a handful of passes on the crate-owned SPIR-V module representation (see passes/).

Pipeline: .air|.ll -> llvm-dis -> sanitize -> native Vulkan SPIR-V emit -> retained crate module -> interface+lowering passes -> assemble -> spirv-val (vulkan1.3).

Modules§

as_shadow
Host-populated metadata view for AIR acceleration-structure introspection.
env_vars
One registry for every METAL2VULKAN_* environment variable the crate honors (refactor S8).
meta
AIR stage-interface metadata, parsed from the ORIGINAL .ll text BEFORE llc runs (llc drops the !air.fragment / !air.vertex metadata nodes). Each entry-function parameter, in SPIR-V OpFunctionParameter order (which llc preserves), gets a role telling the interface pass what Vulkan binding to synthesize for it. Ported faithfully from metal2vulkanspirv::parse_air_fragment_meta, plus a sibling !air.vertex parser the old crate handled structurally rather than from metadata.
native
Native LLVM-IR -> Vulkan SPIR-V emitter.
passes
The residual SPIR-V passes — the stage-interface half of this crate. The structurizer is NOT here: the native emitter (native/, with the structured-control-flow logic in native/cfg/ and native/emitter/control.rs) is what turns the AIR CFG into a structured OpCapability Shader / Logical GLSL450 module, emitting OpSelectionMerge/OpLoopMerge and running the budgeted post-hoc repair. By the time a module reaches these passes it is already structured; what remains is purely the stage interface: the emitter lowers each entry parameter to an opaque pointer/value param and each air.* to an imported function call. The native emitter never emits the legacy LLVM backend’s Linkage capability/decorations. We:
reflect
Public shader-reflection facade.
tools
External-tool runners for metal2vulkan. Production SPIR-V emission is native Rust; the remaining spawns (llvm-dis and spirv-val) are bounded by a timeout so a stuck tool can’t hang the translator.

Functions§

canonicalize_spirv_bytes
Canonicalize the ids of an emitted SPIR-V byte stream into the deterministic serialized-order form the shipped pipeline applies in finish_module. Exposed for the byte-drift gates (historical validation tooling byte-baseline-check/byte-determinism-check`), which compare native-emit output in its canonical (shipped) form rather than the raw emission-order id numbering, which differs benignly between processes and is normalized away here.
detect_stage
Translate an AIR/.ll shader to Vulkan SPIR-V bytes for the given stage. On success returns the assembled SPIR-V words. The caller validates with tools::spirv_val. Detect the shader stage from the AIR’s own !air.vertex/!air.fragment/!air.kernel metadata (which the compiler emits and SPIR-V emission later drops). Lets the caller translate a captured AIR blob without knowing its stage — the kext forwards raw AIR; the stage is intrinsic to the module. A fragment shader run as --stage vertex (or vice-versa) mis-maps the [[position]] role, so detecting beats guessing.
disassemble
Disassemble SPIR-V bytes to spvasm text (for golden fixtures / debugging).
specialize_function_constants
Bake explicit values into a module’s Metal function constants, in place on assembled SPIR-V.
translate
translate_bda_probe
Diagnostic probe: emit the BDA device-pointer tier (emit_vulkan_spirv_all_buffers_raw_bda) for a case and run it through the same finish_module finalization the production bda_retry applies, so the surviving spirv-val residual of a raw store for Ptr(1) BDA case can be inspected. Mirrors translate_raw_tiers_probe; not a frontier signal.
translate_native_no_retry
Emit + passes transform for a sanitized AIR module, stopping BEFORE spirv-val and the retry cascade — the byte-drift-check (BC) gate’s translate path. Returns the canonical SPIR-V bytes the default path would hand to spirv-val on success (Ok), or the emit/passes error (Err). No subprocess and no retry tiers: this is exactly the “primary emit path + passes layer” BC regression-guards, and it is byte-identical to the pre-spirv-val stage of translate_sanitized_native (the same async-copy lowering, meta parse, emit_vulkan_spirv, and finish_module the default path runs before it validates). The retry cascade only fires when this output fails spirv-val, so BC deliberately does NOT see it (retry output needs spirv-val to gate, which the milestone battery’s G4/G5 cover).
translate_native_primary_validated
Return the default-path-aligned PRIMARY candidate without entering the retry cascade. This is intentionally separate from translate_native_no_retry: the byte baseline must stay an in-process, pre-validator gate, while a cross-binding pointer phi can only be adopted after spirv-val proves that it is the actual failing rule. Callers that measure the primary-validity floor use this form with a per-worker temporary directory.
translate_passthrough
Generate a fullscreen-triangle vertex shader whose output interface matches a fragment shader’s [[stage_in]] inputs. Used when APV pipelines bind a built-in vertex slot rather than AIR vertex code.
translate_pre_psb_probe
Diagnostic probe (used by historical PSB dump probes): run the exact production translate path but with the W1 PhysicalStorageBuffer64 retry tiers DISABLED, returning the pre-PSB emission the cascade would otherwise feed to the PSB rewrite. Lets the --psb-dump tool apply rewrite_cross_binding_pointer_merges_bytes by hand for inspection without an env flip (the retired METAL2VULKAN_PSB=0). Not a frontier signal; production always runs with PSB on.
translate_raw_tiers_probe
Probe-only (used by historical raw-residual probes): emit the two R4 raw-retry tiers for a module and return each tier’s emitted+assembled SPIR-V bytes (Ok) or its emit error (Err), through the EXACT same finish_module transform the production retry applies. The caller spirv-vals each to measure the TRUE residual blocker once raw byte-offset modeling resolves the buffer pointer typing: a pointer-merge-classified case whose raw tier emits clean but is then rejected for a CFG/other reason is MULTIPLY-BLOCKED (R4 + R2/…), not a pure R4 case. Returns [tier1, tier2] where tier1 = device/constant buffers raw, tier2 = + threadgroup buffers raw.
translate_reflected
Like translate but also returns the reflect::ShaderReflection — the stage-interface facade (descriptor bindings, vertex attributes, varyings, render targets) the translator already parsed, so a downstream consumer never re-reflects the emitted SPIR-V. The SPIR-V bytes are byte-identical to translate; reflection is a pure re-shaping of the parsed metadata.
translate_reflected_with_options
translate_sanitized_native
Translate already-sanitized LLVM IR through the native emitter. The LLVM llc backend and its crash-workaround passes are not used.
translate_sanitized_native_reflected
translate_sanitized_native_with_options plus the reflection facade. See translate_reflected.
translate_sanitized_native_with_options
translate_with_options