use crate::compile::{CommonOptions, CompiledArtifact};
use spirv_cross_sys as sys;
pub use spirv_cross_sys::MslConstexprSampler as ConstexprSampler;
pub use spirv_cross_sys::MslSamplerAddress as SamplerAddress;
pub use spirv_cross_sys::MslSamplerBorderColor as SamplerBorderColor;
pub use spirv_cross_sys::MslSamplerCompareFunc as SamplerCompareFunc;
pub use spirv_cross_sys::MslSamplerCoord as SamplerCoord;
pub use spirv_cross_sys::MslSamplerFilter as SamplerFilter;
pub use spirv_cross_sys::MslSamplerMipFilter as SamplerMipFilter;
pub use spirv_cross_sys::MslChromaLocation as YcbcrChromaLocation;
pub use spirv_cross_sys::MslComponentSwizzle as YcbcrComponentSwizzle;
pub use spirv_cross_sys::MslFormatResolution as YcbcrFormatResolution;
pub use spirv_cross_sys::MslSamplerYcbcrConversion as SamplerYcbcrConversion;
pub use spirv_cross_sys::MslSamplerYcbcrModelConversion as YcbcrTargetFormat;
pub use spirv_cross_sys::MslSamplerYcbcrRange as YcbcrConversionRange;
pub use spirv_cross_sys::MslShaderVariableFormat as ShaderVariableFormat;
pub use spirv_cross_sys::MslShaderVariableRate as ShaderVariableRate;
pub const MAX_ARGUMENT_BUFFERS: u32 = 8;
use crate::error::ToContextError;
use crate::handle::{Handle, VariableId};
use crate::sealed::Sealed;
use crate::string::CompilerStr;
use crate::targets::Msl;
use crate::{error, Compiler, ContextRooted};
use spirv_cross_sys::{MslResourceBinding2, MslShaderInterfaceVar2, SpvBuiltIn, SpvExecutionModel};
use std::fmt::{Debug, Formatter};
use std::num::NonZeroU32;
impl Sealed for CompilerOptions {}
#[non_exhaustive]
#[derive(Debug, spirv_cross2_derive::CompilerOptions)]
pub struct CompilerOptions {
#[expand]
pub common: CommonOptions,
#[option(SPVC_COMPILER_OPTION_MSL_VERSION)]
pub version: MslVersion,
#[option(SPVC_COMPILER_OPTION_MSL_TEXEL_BUFFER_TEXTURE_WIDTH, 4096)]
pub texel_buffer_texture_width: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SWIZZLE_BUFFER_INDEX, 30)]
pub swizzle_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_INDIRECT_PARAMS_BUFFER_INDEX, 29)]
pub indirect_params_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_OUTPUT_BUFFER_INDEX, 28)]
pub shader_output_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_OUTPUT_BUFFER_INDEX, 27)]
pub shader_patch_output_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_TESS_FACTOR_OUTPUT_BUFFER_INDEX, 26)]
pub shader_tess_factor_output_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_BUFFER_SIZE_BUFFER_INDEX, 25)]
pub buffer_size_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX, 24)]
pub view_mask_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX, 23)]
pub dynamic_offsets_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX, 22)]
pub shader_input_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX, 21)]
pub shader_index_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_INPUT_BUFFER_INDEX, 20)]
pub shader_patch_input_buffer_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_WORKGROUP_INDEX, 0)]
pub shader_input_workgroup_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_BUILTIN, true)]
pub enable_point_size_builtin: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN, true)]
pub enable_frag_depth_builtin: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN, true)]
pub enable_frag_stencil_ref_builtin: bool,
#[option(SPVC_COMPILER_OPTION_MSL_DISABLE_RASTERIZATION, false)]
pub disable_rasterization: bool,
#[option(SPVC_COMPILER_OPTION_MSL_CAPTURE_OUTPUT_TO_BUFFER, false)]
pub capture_output_to_buffer: bool,
#[option(SPVC_COMPILER_OPTION_MSL_SWIZZLE_TEXTURE_SAMPLES, false)]
pub swizzle_texture_samples: bool,
#[option(SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS, false)]
pub pad_fragment_output_components: bool,
#[option(SPVC_COMPILER_OPTION_MSL_TESS_DOMAIN_ORIGIN_LOWER_LEFT, false)]
pub tess_domain_origin_lower_left: bool,
#[option(SPVC_COMPILER_OPTION_MSL_PLATFORM, MetalPlatform::MacOS)]
pub platform: MetalPlatform,
#[option(SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS, false)]
pub argument_buffers: bool,
#[option(
SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS_TIER,
ArgumentBuffersTier::Tier1
)]
pub argument_buffers_tier: ArgumentBuffersTier,
#[option(SPVC_COMPILER_OPTION_MSL_TEXTURE_BUFFER_NATIVE, false)]
pub texture_buffer_native: bool,
#[option(SPVC_COMPILER_OPTION_MSL_MULTIVIEW, false)]
pub multiview: bool,
#[option(SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING, true)]
pub multiview_layered_rendering: bool,
#[option(SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX, 0)]
pub device_index: u32,
#[option(SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX, false)]
pub view_index_from_device_index: bool,
#[option(SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE, false)]
pub dispatch_base: bool,
#[option(SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D, false)]
pub texture_1d_as_2d: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO, false)]
pub enable_base_index_zero: bool,
#[option(SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS, false)]
pub framebuffer_fetch_subpass: bool,
#[option(SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH, false)]
pub invariant_fp_math: bool,
#[option(SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY, false)]
pub emulate_cubemap_array: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING, false)]
pub enable_decoration_binding: bool,
#[option(SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES, false)]
pub force_active_argument_buffer_resources: bool,
#[option(SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS, false)]
pub force_native_arrays: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK, 0xffffffff)]
pub enable_frag_output_mask: u32,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING, true)]
pub enable_clip_distance_user_varying: bool,
#[option(SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP, false)]
pub multi_patch_workgroup: bool,
#[option(SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION, false)]
pub vertex_for_tessellation: bool,
#[option(SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE, IndexType::None)]
pub vertex_index_type: IndexType,
#[option(SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT, false)]
pub arrayed_subpass_input: bool,
#[option(SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT, 4)]
pub r32ui_linear_texture_alignment: u32,
#[option(SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID, 65535)]
pub r32ui_alignment_constant_id: u32,
#[option(SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS, false)]
pub ios_use_simdgroup_functions: bool,
#[option(SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS, false)]
pub emulate_subgroups: bool,
#[option(SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE, 0)]
pub fixed_subgroup_size: u32,
#[option(SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING, false)]
pub force_sample_rate_shading: bool,
#[option(SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE, false)]
pub ios_support_base_vertex_instance: bool,
#[option(SPVC_COMPILER_OPTION_MSL_RAW_BUFFER_TESE_INPUT, false)]
pub raw_buffer_tese_input: bool,
#[option(SPVC_COMPILER_OPTION_MSL_MANUAL_HELPER_INVOCATION_UPDATES, true)]
pub manual_helper_invocation_updates: bool,
#[option(SPVC_COMPILER_OPTION_MSL_CHECK_DISCARDED_FRAG_STORES, false)]
pub check_discarded_frag_stores: bool,
#[option(SPVC_COMPILER_OPTION_MSL_SAMPLE_DREF_LOD_ARRAY_AS_GRAD, false)]
pub sample_dref_lod_array_as_grad: bool,
#[option(SPVC_COMPILER_OPTION_MSL_READWRITE_TEXTURE_FENCES, true)]
pub readwrite_texture_fences: bool,
#[option(SPVC_COMPILER_OPTION_MSL_REPLACE_RECURSIVE_INPUTS, false)]
pub replace_recursive_inputs: bool,
#[option(SPVC_COMPILER_OPTION_MSL_AGX_MANUAL_CUBE_GRAD_FIXUP, false)]
pub agx_manual_cube_grad_fixup: bool,
#[option(
SPVC_COMPILER_OPTION_MSL_FORCE_FRAGMENT_WITH_SIDE_EFFECTS_EXECUTION,
false
)]
pub force_fragment_with_side_effects_execution: bool,
#[option(SPVC_COMPILER_OPTION_MSL_AUTO_DISABLE_RASTERIZATION, false)]
pub auto_disable_rasterization: bool,
#[option(SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_DEFAULT, false)]
pub enable_point_size_default: bool,
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct MslVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
impl MslVersion {
pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
Self {
major,
minor,
patch,
}
}
}
impl Default for MslVersion {
fn default() -> Self {
MslVersion::from((1, 2))
}
}
impl Debug for MslVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"MslVersion({}.{}.{})",
self.major, self.minor, self.patch
)
}
}
impl From<MslVersion> for u32 {
fn from(value: MslVersion) -> Self {
(value.major * 10000) + (value.minor * 100) + value.patch
}
}
impl From<(u32, u32)> for MslVersion {
fn from(value: (u32, u32)) -> Self {
Self {
major: value.0,
minor: value.1,
patch: 0,
}
}
}
impl From<(u32, u32, u32)> for MslVersion {
fn from(value: (u32, u32, u32)) -> Self {
Self {
major: value.0,
minor: value.1,
patch: value.2,
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum ArgumentBuffersTier {
Tier1 = 0,
Tier2 = 1,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum MetalPlatform {
#[allow(non_camel_case_types)]
iOS = 0,
MacOS = 1,
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum IndexType {
None = 0,
Uint16 = 1,
Uint32 = 2,
}
impl From<MetalPlatform> for u32 {
fn from(value: MetalPlatform) -> Self {
match value {
MetalPlatform::iOS => 0,
MetalPlatform::MacOS => 1,
}
}
}
impl From<IndexType> for u32 {
fn from(value: IndexType) -> Self {
match value {
IndexType::None => 0,
IndexType::Uint16 => 1,
IndexType::Uint32 => 1,
}
}
}
impl From<ArgumentBuffersTier> for u32 {
fn from(value: ArgumentBuffersTier) -> Self {
match value {
ArgumentBuffersTier::Tier1 => 0,
ArgumentBuffersTier::Tier2 => 1,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct BufferRequirements {
pub needs_swizzle_buffer: bool,
pub needs_buffer_size_buffer: bool,
pub needs_output_buffer: bool,
pub needs_patch_output_buffer: bool,
pub needs_input_threadgroup_buffer: bool,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ResourceBinding {
Qualified {
set: u32,
binding: u32,
},
PushConstantBuffer,
SwizzleBuffer(u32),
BufferSizeBuffer(u32),
ArgumentBuffer(u32),
}
impl ResourceBinding {
pub const fn from_qualified(set: u32, binding: u32) -> Self {
ResourceBinding::Qualified { set, binding }
}
const fn descriptor_set(&self) -> u32 {
const PUSH_CONSTANT_DESCRIPTOR_SET: u32 = !0;
match self {
ResourceBinding::Qualified { set, .. }
| ResourceBinding::SwizzleBuffer(set)
| ResourceBinding::BufferSizeBuffer(set)
| ResourceBinding::ArgumentBuffer(set) => *set,
ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_DESCRIPTOR_SET,
}
}
const fn binding(&self) -> u32 {
const PUSH_CONSTANT_BINDING: u32 = 0;
const SWIZZLE_BUFFER_BINDING: u32 = !1;
const BUFFER_SIZE_BUFFER_BINDING: u32 = !2;
const ARGUMENT_BUFFER_BINDING: u32 = !3;
match self {
ResourceBinding::Qualified { binding, .. } => *binding,
ResourceBinding::PushConstantBuffer => PUSH_CONSTANT_BINDING,
ResourceBinding::SwizzleBuffer(_) => SWIZZLE_BUFFER_BINDING,
ResourceBinding::BufferSizeBuffer(_) => BUFFER_SIZE_BUFFER_BINDING,
ResourceBinding::ArgumentBuffer(_) => ARGUMENT_BUFFER_BINDING,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BindTarget {
pub buffer: u32,
pub texture: u32,
pub sampler: u32,
pub count: Option<NonZeroU32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ShaderInterfaceVariable {
pub builtin: Option<spirv::BuiltIn>,
pub vecsize: Option<NonZeroU32>,
pub format: ShaderVariableFormat,
pub rate: ShaderVariableRate,
}
impl ShaderInterfaceVariable {
#[must_use]
fn to_raw(&self, location: u32) -> MslShaderInterfaceVar2 {
let mut base = MslShaderInterfaceVar2 {
location,
format: self.format,
builtin: SpvBuiltIn::Position,
vecsize: self.vecsize.map_or(0, NonZeroU32::get),
rate: self.rate,
};
if let Some(builtin) = self.builtin {
base.builtin = SpvBuiltIn(builtin as u32 as i32);
} else {
base.builtin = SpvBuiltIn(i32::MAX);
}
base
}
}
impl Compiler<Msl> {
pub fn is_rasterization_disabled(&self) -> bool {
unsafe { sys::spvc_compiler_msl_is_rasterization_disabled(self.ptr.as_ptr()) }
}
pub fn buffer_requirements(&self) -> BufferRequirements {
unsafe {
let needs_swizzle_buffer =
sys::spvc_compiler_msl_needs_swizzle_buffer(self.ptr.as_ptr());
let needs_buffer_size_buffer =
sys::spvc_compiler_msl_needs_buffer_size_buffer(self.ptr.as_ptr());
let needs_output_buffer = sys::spvc_compiler_msl_needs_output_buffer(self.ptr.as_ptr());
let needs_patch_output_buffer =
sys::spvc_compiler_msl_needs_patch_output_buffer(self.ptr.as_ptr());
let needs_input_threadgroup_buffer =
sys::spvc_compiler_msl_needs_input_threadgroup_mem(self.ptr.as_ptr());
BufferRequirements {
needs_swizzle_buffer,
needs_buffer_size_buffer,
needs_output_buffer,
needs_patch_output_buffer,
needs_input_threadgroup_buffer,
}
}
}
pub fn add_shader_input(
&mut self,
location: u32,
variable: &ShaderInterfaceVariable,
) -> error::Result<()> {
let variable = variable.to_raw(location);
unsafe {
sys::spvc_compiler_msl_add_shader_input_2(self.ptr.as_ptr(), &variable).ok(&*self)
}
}
pub fn add_shader_output(
&mut self,
location: u32,
variable: &ShaderInterfaceVariable,
) -> error::Result<()> {
let variable = variable.to_raw(location);
unsafe {
sys::spvc_compiler_msl_add_shader_output_2(self.ptr.as_ptr(), &variable).ok(&*self)
}
}
pub fn add_resource_binding(
&mut self,
stage: spirv::ExecutionModel,
binding: ResourceBinding,
bind_target: &BindTarget,
) -> error::Result<()> {
let binding = MslResourceBinding2 {
stage: SpvExecutionModel(stage as u32 as i32),
desc_set: binding.descriptor_set(),
binding: binding.binding(),
count: bind_target.count.map_or(0, NonZeroU32::get),
msl_buffer: bind_target.buffer,
msl_texture: bind_target.texture,
msl_sampler: bind_target.sampler,
};
unsafe {
sys::spvc_compiler_msl_add_resource_binding_2(self.ptr.as_ptr(), &binding).ok(&*self)
}
}
pub fn add_discrete_descriptor_set(&mut self, desc_set: u32) -> error::Result<()> {
unsafe {
sys::spvc_compiler_msl_add_discrete_descriptor_set(self.ptr.as_ptr(), desc_set)
.ok(&*self)
}
}
pub fn add_dynamic_buffer(
&mut self,
desc_set: u32,
binding: u32,
index: u32,
) -> error::Result<()> {
unsafe {
sys::spvc_compiler_msl_add_dynamic_buffer(self.ptr.as_ptr(), desc_set, binding, index)
.ok(&*self)
}
}
pub fn add_inline_uniform_block(&mut self, desc_set: u32, binding: u32) -> error::Result<()> {
unsafe {
sys::spvc_compiler_msl_add_inline_uniform_block(self.ptr.as_ptr(), desc_set, binding)
.ok(&*self)
}
}
pub fn set_argument_buffer_device_address_space(
&mut self,
desc_set: u32,
device_address: bool,
) -> error::Result<()> {
unsafe {
sys::spvc_compiler_msl_set_argument_buffer_device_address_space(
self.ptr.as_ptr(),
desc_set,
device_address,
)
.ok(&*self)
}
}
pub fn remap_constexpr_sampler(
&mut self,
variable: impl Into<Handle<VariableId>>,
sampler: &ConstexprSampler,
ycbcr: Option<&SamplerYcbcrConversion>,
) -> error::Result<()> {
let variable = variable.into();
let id = self.yield_id(variable)?;
if let Some(ycbcr) = ycbcr {
unsafe {
sys::spvc_compiler_msl_remap_constexpr_sampler_ycbcr(
self.ptr.as_ptr(),
id,
sampler,
ycbcr,
)
.ok(&*self)
}
} else {
unsafe {
sys::spvc_compiler_msl_remap_constexpr_sampler(self.ptr.as_ptr(), id, sampler)
.ok(&*self)
}
}
}
pub fn remap_constexpr_sampler_by_binding(
&mut self,
desc_set: u32,
binding: u32,
sampler: &ConstexprSampler,
ycbcr: Option<&SamplerYcbcrConversion>,
) -> error::Result<()> {
if let Some(ycbcr) = ycbcr {
unsafe {
sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(
self.ptr.as_ptr(),
desc_set,
binding,
sampler,
ycbcr,
)
.ok(&*self)
}
} else {
unsafe {
sys::spvc_compiler_msl_remap_constexpr_sampler_by_binding(
self.ptr.as_ptr(),
desc_set,
binding,
sampler,
)
.ok(&*self)
}
}
}
pub fn set_fragment_output_components(
&mut self,
location: u32,
components: u32,
) -> error::Result<()> {
unsafe {
sys::spvc_compiler_msl_set_fragment_output_components(
self.ptr.as_ptr(),
location,
components,
)
.ok(&*self)
}
}
pub fn set_combined_sampler_suffix<'str>(
&mut self,
str: impl Into<CompilerStr<'str>>,
) -> error::Result<()> {
unsafe {
let str = str.into();
let suffix = str.into_cstring_ptr()?;
sys::spvc_compiler_msl_set_combined_sampler_suffix(self.ptr.as_ptr(), suffix.as_ptr())
.ok(&*self)
}
}
pub fn combined_sampler_suffix(&self) -> CompilerStr<'_> {
unsafe {
let suffix = sys::spvc_compiler_msl_get_combined_sampler_suffix(self.ptr.as_ptr());
CompilerStr::from_ptr(suffix, self.ctx.drop_guard())
}
}
pub fn mask_stage_output_by_location(
&mut self,
location: u32,
component: u32,
) -> crate::error::Result<()> {
unsafe {
sys::spvc_compiler_mask_stage_output_by_location(self.ptr.as_ptr(), location, component)
.ok(&*self)
}
}
pub fn mask_stage_output_by_builtin(
&mut self,
builtin: spirv::BuiltIn,
) -> crate::error::Result<()> {
unsafe {
sys::spvc_compiler_mask_stage_output_by_builtin(
self.ptr.as_ptr(),
SpvBuiltIn(builtin as u32 as i32),
)
.ok(&*self)
}
}
}
#[derive(Copy, Clone, Debug, Default)]
#[non_exhaustive]
pub enum AutomaticResourceBindingTier {
#[default]
Primary,
Secondary,
}
impl CompiledArtifact<Msl> {
pub fn is_resource_used(&self, model: spirv::ExecutionModel, binding: ResourceBinding) -> bool {
unsafe {
sys::spvc_compiler_msl_is_resource_used(
self.compiler.ptr.as_ptr(),
SpvExecutionModel(model as u32 as i32),
binding.descriptor_set(),
binding.binding(),
)
}
}
pub fn is_shader_input_used(&self, location: u32) -> bool {
unsafe { sys::spvc_compiler_msl_is_shader_input_used(self.compiler.ptr.as_ptr(), location) }
}
pub fn is_shader_output_used(&self, location: u32) -> bool {
unsafe {
sys::spvc_compiler_msl_is_shader_output_used(self.compiler.ptr.as_ptr(), location)
}
}
pub fn automatic_resource_binding(
&self,
handle: impl Into<Handle<VariableId>>,
tier: AutomaticResourceBindingTier,
) -> error::Result<Option<u32>> {
let handle = handle.into();
let id = self.yield_id(handle)?;
let res = match tier {
AutomaticResourceBindingTier::Primary => unsafe {
sys::spvc_compiler_msl_get_automatic_resource_binding(self.ptr.as_ptr(), id)
},
AutomaticResourceBindingTier::Secondary => unsafe {
sys::spvc_compiler_msl_get_automatic_resource_binding_secondary(
self.ptr.as_ptr(),
id,
)
},
};
if res == u32::MAX {
Ok(None)
} else {
Ok(Some(res))
}
}
pub fn variable_is_depth_or_compare(
&self,
variable: impl Into<Handle<VariableId>>,
) -> error::Result<bool> {
let variable = variable.into();
let id = self.yield_id(variable)?;
unsafe {
Ok(sys::spvc_compiler_variable_is_depth_or_compare(
self.ptr.as_ptr(),
id,
))
}
}
}
#[cfg(test)]
mod test {
use crate::compile::msl::CompilerOptions;
use spirv_cross_sys::spvc_compiler_create_compiler_options;
use crate::compile::sealed::ApplyCompilerOptions;
use crate::error::{SpirvCrossError, ToContextError};
use crate::Compiler;
use crate::{targets, Module};
static BASIC_SPV: &[u8] = include_bytes!("../../../basic.spv");
#[test]
pub fn msl_opts() -> Result<(), SpirvCrossError> {
let words = Vec::from(BASIC_SPV);
let words = Module::from_words(bytemuck::cast_slice(&words));
let compiler: Compiler<targets::Msl> = Compiler::new(words)?;
let resources = compiler.shader_resources()?.all_resources()?;
let mut opts_ptr = std::ptr::null_mut();
unsafe {
spvc_compiler_create_compiler_options(compiler.ptr.as_ptr(), &mut opts_ptr)
.ok(&compiler)?;
}
let opts = CompilerOptions::default();
unsafe {
opts.apply(opts_ptr, &compiler)?;
}
Ok(())
}
}