diff options
Diffstat (limited to 'third_party/rust/spirv-cross-internal/src/msl.rs')
-rw-r--r-- | third_party/rust/spirv-cross-internal/src/msl.rs | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/third_party/rust/spirv-cross-internal/src/msl.rs b/third_party/rust/spirv-cross-internal/src/msl.rs new file mode 100644 index 0000000000..18f45a2ebf --- /dev/null +++ b/third_party/rust/spirv-cross-internal/src/msl.rs @@ -0,0 +1,545 @@ +use crate::bindings as br; +use crate::{compiler, spirv, ErrorCode}; + +use std::collections::BTreeMap; +use std::ffi::{CStr, CString}; +use std::marker::PhantomData; +use std::ptr; +use std::u8; + +/// A MSL target. +#[derive(Debug, Clone)] +pub enum Target {} + +pub struct TargetData { + vertex_attribute_overrides: Vec<br::spirv_cross::MSLShaderInput>, + resource_binding_overrides: Vec<br::spirv_cross::MSLResourceBinding>, + const_samplers: Vec<br::ScMslConstSamplerMapping>, +} + +impl spirv::Target for Target { + type Data = TargetData; +} + +/// Location of a vertex attribute to override +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct VertexAttributeLocation(pub u32); + +/// Format of the vertex attribute +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub enum Format { + Other, + Uint8, + Uint16, +} + +impl Format { + fn as_raw(&self) -> br::spirv_cross::MSLShaderInputFormat { + use self::Format::*; + match self { + Other => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_OTHER, + Uint8 => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_UINT8, + Uint16 => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_UINT16, + } + } +} + +/// Vertex attribute description for overriding +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct VertexAttribute { + pub buffer_id: u32, + pub format: Format, + pub built_in: Option<spirv::BuiltIn>, + pub vecsize: u32, +} + +/// Location of a resource binding to override +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct ResourceBindingLocation { + pub stage: spirv::ExecutionModel, + pub desc_set: u32, + pub binding: u32, +} + +/// Resource binding description for overriding +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct ResourceBinding { + pub buffer_id: u32, + pub texture_id: u32, + pub sampler_id: u32, +} + +/// Location of a sampler binding to override +#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct SamplerLocation { + pub desc_set: u32, + pub binding: u32, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerCoord { + Normalized = 0, + Pixel = 1, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerFilter { + Nearest = 0, + Linear = 1, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerMipFilter { + None = 0, + Nearest = 1, + Linear = 2, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerAddress { + ClampToZero = 0, + ClampToEdge = 1, + ClampToBorder = 2, + Repeat = 3, + MirroredRepeat = 4, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerCompareFunc { + Never = 0, + Less = 1, + LessEqual = 2, + Greater = 3, + GreaterEqual = 4, + Equal = 5, + NotEqual = 6, + Always = 7, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum SamplerBorderColor { + TransparentBlack = 0, + OpaqueBlack = 1, + OpaqueWhite = 2, +} + +#[repr(transparent)] +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub struct LodBase16(u8); + +impl LodBase16 { + pub const ZERO: Self = LodBase16(0); + pub const MAX: Self = LodBase16(!0); +} + +impl From<f32> for LodBase16 { + fn from(v: f32) -> Self { + LodBase16((v * 16.0).max(0.0).min(u8::MAX as f32) as u8) + } +} + +impl Into<f32> for LodBase16 { + fn into(self) -> f32 { + self.0 as f32 / 16.0 + } +} + +/// MSL format resolution. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum FormatResolution { + _444 = 0, + _422 = 1, + _420 = 2, +} + +/// MSL chroma location. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ChromaLocation { + CositedEven = 0, + LocationMidpoint = 1, +} + +/// MSL component swizzle. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ComponentSwizzle { + Identity = 0, + Zero = 1, + One = 2, + R = 3, + G = 4, + B = 5, + A = 6, +} + +/// Data fully defining a constant sampler. +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct SamplerData { + pub coord: SamplerCoord, + pub min_filter: SamplerFilter, + pub mag_filter: SamplerFilter, + pub mip_filter: SamplerMipFilter, + pub s_address: SamplerAddress, + pub t_address: SamplerAddress, + pub r_address: SamplerAddress, + pub compare_func: SamplerCompareFunc, + pub border_color: SamplerBorderColor, + pub lod_clamp_min: LodBase16, + pub lod_clamp_max: LodBase16, + pub max_anisotropy: i32, + // Sampler YCbCr conversion parameters + pub planes: u32, + pub resolution: FormatResolution, + pub chroma_filter: SamplerFilter, + pub x_chroma_offset: ChromaLocation, + pub y_chroma_offset: ChromaLocation, + pub swizzle: [ComponentSwizzle; 4], + pub ycbcr_conversion_enable: bool, + pub ycbcr_model: SamplerYCbCrModelConversion, + pub ycbcr_range: SamplerYCbCrRange, + pub bpc: u32, +} + +/// A MSL sampler YCbCr model conversion. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum SamplerYCbCrModelConversion { + RgbIdentity = 0, + YCbCrIdentity = 1, + YCbCrBt709 = 2, + YCbCrBt601 = 3, + YCbCrBt2020 = 4, +} + +/// A MSL sampler YCbCr range. +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum SamplerYCbCrRange { + ItuFull = 0, + ItuNarrow = 1, +} + +/// A MSL shader platform. +#[repr(u8)] +#[allow(non_snake_case, non_camel_case_types)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum Platform { + iOS = 0, + macOS = 1, +} + +/// A MSL shader model version. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum Version { + V1_0, + V1_1, + V1_2, + V2_0, + V2_1, + V2_2, +} + +impl Version { + fn as_raw(self) -> u32 { + use self::Version::*; + match self { + V1_0 => 10000, + V1_1 => 10100, + V1_2 => 10200, + V2_0 => 20000, + V2_1 => 20100, + V2_2 => 20200, + } + } +} + +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct CompilerVertexOptions { + pub invert_y: bool, + pub transform_clip_space: bool, +} + +impl Default for CompilerVertexOptions { + fn default() -> Self { + CompilerVertexOptions { + invert_y: false, + transform_clip_space: false, + } + } +} + +/// MSL compiler options. +#[non_exhaustive] +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct CompilerOptions { + /// The target platform. + pub platform: Platform, + /// The target MSL version. + pub version: Version, + /// Vertex compiler options. + pub vertex: CompilerVertexOptions, + /// The buffer index to use for swizzle. + pub swizzle_buffer_index: u32, + // The buffer index to use for indirect params. + pub indirect_params_buffer_index: u32, + /// The buffer index to use for output. + pub output_buffer_index: u32, + /// The buffer index to use for patch output. + pub patch_output_buffer_index: u32, + /// The buffer index to use for tessellation factor. + pub tessellation_factor_buffer_index: u32, + /// The buffer index to use for buffer size. + pub buffer_size_buffer_index: u32, + /// Whether the built-in point size should be enabled. + pub enable_point_size_builtin: bool, + /// Whether rasterization should be enabled. + pub enable_rasterization: bool, + /// Whether to capture output to buffer. + pub capture_output_to_buffer: bool, + /// Whether to swizzle texture samples. + pub swizzle_texture_samples: bool, + /// Whether to place the origin of tessellation domain shaders in the lower left. + pub tessellation_domain_origin_lower_left: bool, + /// Whether to enable use of argument buffers (only compatible with MSL 2.0). + pub enable_argument_buffers: bool, + /// Whether to pad fragment output to have at least the number of components as the render pass. + pub pad_fragment_output_components: bool, + /// MSL resource bindings overrides. + pub resource_binding_overrides: BTreeMap<ResourceBindingLocation, ResourceBinding>, + /// MSL vertex attribute overrides. + pub vertex_attribute_overrides: BTreeMap<VertexAttributeLocation, VertexAttribute>, + /// MSL const sampler mappings. + pub const_samplers: BTreeMap<SamplerLocation, SamplerData>, + /// Whether to force native arrays (useful to workaround issues on some hardware). + pub force_native_arrays: bool, + /// Whether to force all uninitialized variables to be initialized to zero. + pub force_zero_initialized_variables: bool, + /// The name and execution model of the entry point to use. If no entry + /// point is specified, then the first entry point found will be used. + pub entry_point: Option<(String, spirv::ExecutionModel)>, +} + +impl Default for CompilerOptions { + fn default() -> Self { + CompilerOptions { + platform: Platform::macOS, + version: Version::V1_2, + vertex: CompilerVertexOptions::default(), + swizzle_buffer_index: 30, + indirect_params_buffer_index: 29, + output_buffer_index: 28, + patch_output_buffer_index: 27, + tessellation_factor_buffer_index: 26, + buffer_size_buffer_index: 25, + enable_point_size_builtin: true, + enable_rasterization: true, + capture_output_to_buffer: false, + swizzle_texture_samples: false, + tessellation_domain_origin_lower_left: false, + enable_argument_buffers: false, + pad_fragment_output_components: false, + resource_binding_overrides: Default::default(), + vertex_attribute_overrides: Default::default(), + const_samplers: Default::default(), + force_native_arrays: false, + force_zero_initialized_variables: false, + entry_point: None, + } + } +} + +impl<'a> spirv::Parse<Target> for spirv::Ast<Target> { + fn parse(module: &spirv::Module) -> Result<Self, ErrorCode> { + let mut sc_compiler = ptr::null_mut(); + unsafe { + check!(br::sc_internal_compiler_msl_new( + &mut sc_compiler, + module.words.as_ptr(), + module.words.len(), + )); + } + + Ok(spirv::Ast { + compiler: compiler::Compiler { + sc_compiler, + target_data: TargetData { + resource_binding_overrides: Vec::new(), + vertex_attribute_overrides: Vec::new(), + const_samplers: Vec::new(), + }, + has_been_compiled: false, + }, + target_type: PhantomData, + }) + } +} + +impl spirv::Compile<Target> for spirv::Ast<Target> { + type CompilerOptions = CompilerOptions; + + /// Set MSL compiler specific compilation settings. + fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> { + if let Some((name, model)) = &options.entry_point { + let name_raw = CString::new(name.as_str()).map_err(|_| ErrorCode::Unhandled)?; + let model = model.as_raw(); + unsafe { + check!(br::sc_internal_compiler_set_entry_point( + self.compiler.sc_compiler, + name_raw.as_ptr(), + model, + )); + } + }; + let raw_options = br::ScMslCompilerOptions { + vertex_invert_y: options.vertex.invert_y, + vertex_transform_clip_space: options.vertex.transform_clip_space, + platform: options.platform as _, + version: options.version.as_raw(), + enable_point_size_builtin: options.enable_point_size_builtin, + disable_rasterization: !options.enable_rasterization, + swizzle_buffer_index: options.swizzle_buffer_index, + indirect_params_buffer_index: options.indirect_params_buffer_index, + shader_output_buffer_index: options.output_buffer_index, + shader_patch_output_buffer_index: options.patch_output_buffer_index, + shader_tess_factor_buffer_index: options.tessellation_factor_buffer_index, + buffer_size_buffer_index: options.buffer_size_buffer_index, + capture_output_to_buffer: options.capture_output_to_buffer, + swizzle_texture_samples: options.swizzle_texture_samples, + tess_domain_origin_lower_left: options.tessellation_domain_origin_lower_left, + argument_buffers: options.enable_argument_buffers, + pad_fragment_output_components: options.pad_fragment_output_components, + force_native_arrays: options.force_native_arrays, + force_zero_initialized_variables: options.force_zero_initialized_variables, + }; + unsafe { + check!(br::sc_internal_compiler_msl_set_options( + self.compiler.sc_compiler, + &raw_options, + )); + } + + self.compiler.target_data.resource_binding_overrides.clear(); + self.compiler.target_data.resource_binding_overrides.extend( + options.resource_binding_overrides.iter().map(|(loc, res)| { + br::spirv_cross::MSLResourceBinding { + stage: loc.stage.as_raw(), + desc_set: loc.desc_set, + binding: loc.binding, + msl_buffer: res.buffer_id, + msl_texture: res.texture_id, + msl_sampler: res.sampler_id, + } + }), + ); + + self.compiler.target_data.vertex_attribute_overrides.clear(); + self.compiler.target_data.vertex_attribute_overrides.extend( + options.vertex_attribute_overrides.iter().map(|(loc, vat)| { + br::spirv_cross::MSLShaderInput { + location: loc.0, + format: vat.format.as_raw(), + builtin: spirv::built_in_as_raw(vat.built_in), + vecsize: vat.vecsize, + } + }), + ); + + self.compiler.target_data.const_samplers.clear(); + self.compiler + .target_data + .const_samplers + .extend(options.const_samplers.iter().map(|(loc, data)| unsafe { + use std::mem::transmute; + br::ScMslConstSamplerMapping { + desc_set: loc.desc_set, + binding: loc.binding, + sampler: br::spirv_cross::MSLConstexprSampler { + coord: transmute(data.coord), + min_filter: transmute(data.min_filter), + mag_filter: transmute(data.mag_filter), + mip_filter: transmute(data.mip_filter), + s_address: transmute(data.s_address), + t_address: transmute(data.t_address), + r_address: transmute(data.r_address), + compare_func: transmute(data.compare_func), + border_color: transmute(data.border_color), + lod_clamp_min: data.lod_clamp_min.into(), + lod_clamp_max: data.lod_clamp_max.into(), + max_anisotropy: data.max_anisotropy, + compare_enable: data.compare_func != SamplerCompareFunc::Always, + lod_clamp_enable: data.lod_clamp_min != LodBase16::ZERO + || data.lod_clamp_max != LodBase16::MAX, + anisotropy_enable: data.max_anisotropy != 0, + bpc: data.bpc, + chroma_filter: transmute(data.chroma_filter), + planes: data.planes, + resolution: transmute(data.resolution), + swizzle: transmute(data.swizzle), + x_chroma_offset: transmute(data.x_chroma_offset), + y_chroma_offset: transmute(data.y_chroma_offset), + ycbcr_conversion_enable: data.ycbcr_conversion_enable, + ycbcr_model: transmute(data.ycbcr_model), + ycbcr_range: transmute(data.ycbcr_range), + }, + } + })); + + Ok(()) + } + + /// Generate MSL shader from the AST. + fn compile(&mut self) -> Result<String, ErrorCode> { + self.compile_internal() + } +} + +impl spirv::Ast<Target> { + fn compile_internal(&self) -> Result<String, ErrorCode> { + let vat_overrides = &self.compiler.target_data.vertex_attribute_overrides; + let res_overrides = &self.compiler.target_data.resource_binding_overrides; + let const_samplers = &self.compiler.target_data.const_samplers; + unsafe { + let mut shader_ptr = ptr::null(); + check!(br::sc_internal_compiler_msl_compile( + self.compiler.sc_compiler, + &mut shader_ptr, + vat_overrides.as_ptr(), + vat_overrides.len(), + res_overrides.as_ptr(), + res_overrides.len(), + const_samplers.as_ptr(), + const_samplers.len(), + )); + let shader = match CStr::from_ptr(shader_ptr).to_str() { + Ok(v) => v.to_owned(), + Err(_) => return Err(ErrorCode::Unhandled), + }; + check!(br::sc_internal_free_pointer( + shader_ptr as *mut std::os::raw::c_void + )); + Ok(shader) + } + } + + pub fn is_rasterization_enabled(&self) -> Result<bool, ErrorCode> { + unsafe { + let mut is_disabled = false; + check!(br::sc_internal_compiler_msl_get_is_rasterization_disabled( + self.compiler.sc_compiler, + &mut is_disabled + )); + Ok(!is_disabled) + } + } +} + +// TODO: Generate with bindgen +pub const ARGUMENT_BUFFER_BINDING: u32 = !3; |