From c3033cfbbf7ee2bbd6aa79bd36dd3957818046fd Mon Sep 17 00:00:00 2001 From: chyyran Date: Wed, 4 Sep 2024 20:49:20 -0400 Subject: [PATCH] reflect: port to spirv-cross2 --- Cargo.lock | 64 ++- Cargo.toml | 3 +- librashader-capi/Cargo.toml | 1 - librashader-reflect/Cargo.toml | 14 +- librashader-reflect/src/back/glsl.rs | 4 +- librashader-reflect/src/back/hlsl.rs | 4 +- librashader-reflect/src/back/msl.rs | 6 +- librashader-reflect/src/error.rs | 4 +- librashader-reflect/src/reflect/cross/glsl.rs | 135 +++--- librashader-reflect/src/reflect/cross/hlsl.rs | 96 +++-- librashader-reflect/src/reflect/cross/mod.rs | 388 ++++++++++-------- librashader-reflect/src/reflect/cross/msl.rs | 144 +++---- librashader-reflect/src/reflect/naga/mod.rs | 9 +- librashader-reflect/src/reflect/naga/msl.rs | 14 +- librashader-runtime-d3d12/src/filter_chain.rs | 2 +- librashader-runtime-d3d9/src/filter_chain.rs | 2 +- librashader-runtime-gl/Cargo.toml | 2 +- librashader-runtime-gl/src/error.rs | 2 +- .../src/gl/gl3/compile_program.rs | 18 +- .../src/gl/gl46/compile_program.rs | 18 +- librashader-runtime-gl/src/util.rs | 52 +-- librashader-runtime-mtl/src/filter_chain.rs | 2 +- librashader/src/lib.rs | 2 - 23 files changed, 549 insertions(+), 437 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 355152f..0731a33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -411,9 +411,9 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] @@ -1678,7 +1678,6 @@ dependencies = [ "ash", "gl", "librashader", - "librashader-spirv-cross", "objc2 0.5.2", "objc2-metal", "paste", @@ -1741,13 +1740,13 @@ dependencies = [ "librashader-common", "librashader-preprocess", "librashader-presets", - "librashader-spirv-cross", "matches", "naga", "rspirv", "rustc-hash 2.0.0", "serde", "spirv", + "spirv-cross2", "spirv-to-dxil", "thiserror", ] @@ -1842,8 +1841,8 @@ dependencies = [ "librashader-presets", "librashader-reflect", "librashader-runtime", - "librashader-spirv-cross", "rayon", + "spirv-cross2", "sptr", "thiserror", ] @@ -1914,18 +1913,6 @@ dependencies = [ "winit", ] -[[package]] -name = "librashader-spirv-cross" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4603464191d79d8ce9fe81f7925dfa5b74060b15be51608525f0758f6d88e238" -dependencies = [ - "build-target", - "cc", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "libredox" version = "0.0.2" @@ -2936,9 +2923,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ "bitflags 2.6.0", "errno", @@ -3147,6 +3134,45 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "spirv-cross-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aaad7cc693a12f8da9fd481ac938fdd0fc1b2e73b9f710eb723d3e7f5607f0a" +dependencies = [ + "bytemuck", + "cc", + "glob", + "num-derive", + "num-traits", +] + +[[package]] +name = "spirv-cross2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f49915b223bae37821a45c93ad5c269cb6df620b4147b567cda4cf8951061e" +dependencies = [ + "bitflags 2.6.0", + "bytemuck", + "memchr", + "spirv", + "spirv-cross-sys", + "spirv-cross2-derive", + "thiserror", +] + +[[package]] +name = "spirv-cross2-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18017a288e6ce64dd5d56510166baeabb01849483555c031f573c091b6934a64" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "spirv-to-dxil" version = "0.4.7" diff --git a/Cargo.toml b/Cargo.toml index 20b0cb3..a24e553 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,7 @@ resolver = "2" [workspace.dependencies] windows = "0.58.0" ash = "0.38" -spirv_cross = { package = "librashader-spirv-cross", version = "0.26" } - +spirv-cross2 = { version = "0.4", default-features = false } objc2-metal = { version = "0.2" } objc2 = { version = "0.5.0" } diff --git a/librashader-capi/Cargo.toml b/librashader-capi/Cargo.toml index 98f761d..348ec15 100644 --- a/librashader-capi/Cargo.toml +++ b/librashader-capi/Cargo.toml @@ -42,7 +42,6 @@ rustc-hash = "2.0.0" sptr = "0.3.2" ash = { workspace = true, optional = true } -spirv_cross = { workspace = true } [dependencies.librashader] path = "../librashader" diff --git a/librashader-reflect/Cargo.toml b/librashader-reflect/Cargo.toml index 327fe5f..d7bf50e 100644 --- a/librashader-reflect/Cargo.toml +++ b/librashader-reflect/Cargo.toml @@ -22,7 +22,7 @@ librashader-common = { path = "../librashader-common", version = "0.3.3" } librashader-preprocess = { path = "../librashader-preprocess", version = "0.3.3" } librashader-presets = { path = "../librashader-presets", version = "0.3.3" } -spirv_cross = { workspace = true, optional = true } +spirv-cross2 = { workspace = true, optional = true } naga = { version = "22", optional = true } rspirv = { version = "0.12.0", optional = true } @@ -40,11 +40,11 @@ optional = true [features] default = ["cross", "naga", "serialize", "wgsl", "msl"] -dxil = ["spirv_cross/hlsl", "spirv-to-dxil"] -wgsl = ["cross", "naga/wgsl-out", "spirv", "rspirv"] -cross = [ "spirv_cross", "spirv_cross/glsl", "spirv_cross/hlsl", "spirv_cross/msl" ] -naga = [ "rspirv", "spirv", "naga/spv-in", "naga/spv-out", "naga/wgsl-out", "naga/msl-out" ] -serialize = [ "serde" ] -msl = [ "spirv_cross/msl", "naga/msl-out" ] +dxil = ["spirv-cross2/hlsl", "dep:spirv-to-dxil"] +wgsl = ["cross", "naga/wgsl-out", "dep:spirv", "dep:rspirv"] +cross = [ "dep:spirv-cross2", "spirv-cross2/glsl", "spirv-cross2/hlsl", "spirv-cross2/msl" ] +naga = [ "dep:rspirv", "dep:spirv", "naga/spv-in", "naga/spv-out", "naga/wgsl-out", "naga/msl-out" ] +serialize = [ "dep:serde" ] +msl = [ "spirv-cross2/msl", "naga/msl-out" ] unstable-naga-in = ["naga/glsl-in"] diff --git a/librashader-reflect/src/back/glsl.rs b/librashader-reflect/src/back/glsl.rs index c73514b..64d8823 100644 --- a/librashader-reflect/src/back/glsl.rs +++ b/librashader-reflect/src/back/glsl.rs @@ -6,7 +6,7 @@ use crate::reflect::cross::{CompiledProgram, SpirvCross}; use crate::reflect::ReflectShader; /// The GLSL version to target. -pub use spirv_cross::glsl::Version as GlslVersion; +pub use spirv_cross2::compile::glsl::GlslVersion; use crate::reflect::cross::glsl::GlslReflect; @@ -15,7 +15,7 @@ pub struct CrossGlslContext { /// A map of bindings of sampler names to binding locations. pub sampler_bindings: Vec<(String, u32)>, /// The compiled program artifact after compilation. - pub artifact: CompiledProgram, + pub artifact: CompiledProgram, } impl FromCompilation for GLSL { diff --git a/librashader-reflect/src/back/hlsl.rs b/librashader-reflect/src/back/hlsl.rs index fa944dc..1b4da9b 100644 --- a/librashader-reflect/src/back/hlsl.rs +++ b/librashader-reflect/src/back/hlsl.rs @@ -7,7 +7,7 @@ use crate::reflect::cross::{CompiledProgram, SpirvCross}; use crate::reflect::ReflectShader; /// The HLSL shader model version to target. -pub use spirv_cross::hlsl::ShaderModel as HlslShaderModel; +pub use spirv_cross2::compile::hlsl::HlslShaderModel; /// Buffer assignment information #[derive(Debug, Clone)] @@ -99,7 +99,7 @@ impl HlslBufferAssignments { /// The context for a HLSL compilation via spirv-cross. pub struct CrossHlslContext { /// The compiled HLSL program. - pub artifact: CompiledProgram, + pub artifact: CompiledProgram, pub vertex_buffers: HlslBufferAssignments, pub fragment_buffers: HlslBufferAssignments, } diff --git a/librashader-reflect/src/back/msl.rs b/librashader-reflect/src/back/msl.rs index 3a2f857..1c9a7fa 100644 --- a/librashader-reflect/src/back/msl.rs +++ b/librashader-reflect/src/back/msl.rs @@ -9,8 +9,8 @@ use crate::reflect::ReflectShader; use naga::back::msl::TranslationInfo; use naga::Module; -/// The HLSL shader model version to target. -pub use spirv_cross::msl::Version as MslVersion; +/// The MSL language version to target. +pub use spirv_cross2::compile::msl::MslVersion; /// Compiler options for MSL #[derive(Debug, Default, Clone)] @@ -22,7 +22,7 @@ pub struct MslNagaCompileOptions { /// The context for a MSL compilation via spirv-cross. pub struct CrossMslContext { /// The compiled HLSL program. - pub artifact: CompiledProgram, + pub artifact: CompiledProgram, } impl FromCompilation for MSL { diff --git a/librashader-reflect/src/error.rs b/librashader-reflect/src/error.rs index d7d72ca..8461d7c 100644 --- a/librashader-reflect/src/error.rs +++ b/librashader-reflect/src/error.rs @@ -20,7 +20,7 @@ pub enum ShaderCompileError { /// Error when transpiling from spirv-cross. #[error("spirv-cross error: {0:?}")] - SpirvCrossCompileError(#[from] spirv_cross::ErrorCode), + SpirvCrossCompileError(#[from] spirv_cross2::SpirvCrossError), /// Error when transpiling from spirv-to-dxil #[cfg(all(target_os = "windows", feature = "dxil"))] @@ -87,7 +87,7 @@ pub enum SemanticsErrorKind { pub enum ShaderReflectError { /// Reflection error from spirv-cross. #[error("spirv cross error: {0}")] - SpirvCrossError(#[from] spirv_cross::ErrorCode), + SpirvCrossError(#[from] spirv_cross2::SpirvCrossError), /// Error when validating vertex shader semantics. #[error("error when verifying vertex semantics: {0:?}")] VertexSemanticError(SemanticsErrorKind), diff --git a/librashader-reflect/src/reflect/cross/glsl.rs b/librashader-reflect/src/reflect/cross/glsl.rs index 9e35cc3..e42e914 100644 --- a/librashader-reflect/src/reflect/cross/glsl.rs +++ b/librashader-reflect/src/reflect/cross/glsl.rs @@ -2,136 +2,165 @@ use crate::back::glsl::CrossGlslContext; use crate::back::targets::GLSL; use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::error::ShaderCompileError; -use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; -use spirv_cross::spirv::Decoration; -use spirv_cross::ErrorCode; +use crate::reflect::cross::{CompiledProgram, CrossReflect}; +use spirv::Decoration; -pub(crate) type GlslReflect = CrossReflect; +use spirv_cross2::compile::CompilableTarget; +use spirv_cross2::reflect::{DecorationValue, ResourceType}; +use spirv_cross2::{targets, SpirvCrossError}; -impl CompileShader for CrossReflect { - type Options = spirv_cross::glsl::Version; +pub(crate) type GlslReflect = CrossReflect; + +impl CompileShader for CrossReflect { + type Options = spirv_cross2::compile::glsl::GlslVersion; type Context = CrossGlslContext; fn compile( mut self, version: Self::Options, ) -> Result, ShaderCompileError> { - let mut options: spirv_cross::glsl::CompilerOptions = Default::default(); + let mut options = targets::Glsl::options(); + options.version = version; - options.fragment.default_float_precision = spirv_cross::glsl::Precision::High; - options.fragment.default_int_precision = spirv_cross::glsl::Precision::High; - options.enable_420_pack_extension = false; - self.vertex.set_compiler_options(&options)?; - self.fragment.set_compiler_options(&options)?; + options.es_default_float_precision_highp = true; + options.es_default_int_precision_highp = true; + options.enable_420pack_extension = false; - let vertex_resources = self.vertex.get_shader_resources()?; - let fragment_resources = self.fragment.get_shader_resources()?; + let vertex_resources = self.vertex.shader_resources()?; + let fragment_resources = self.fragment.shader_resources()?; - for res in &vertex_resources.stage_outputs { + for res in vertex_resources.resources_for_type(ResourceType::StageOutput)? { // let location = self.vertex.get_decoration(res.id, Decoration::Location)?; // self.vertex // .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?; - self.vertex.unset_decoration(res.id, Decoration::Location)?; + self.vertex + .set_decoration(res.id, Decoration::Location, DecorationValue::unset())?; } - for res in &fragment_resources.stage_inputs { + for res in fragment_resources.resources_for_type(ResourceType::StageInput)? { // let location = self.fragment.get_decoration(res.id, Decoration::Location)?; // self.fragment // .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?; self.fragment - .unset_decoration(res.id, Decoration::Location)?; + .set_decoration(res.id, Decoration::Location, DecorationValue::unset())?; } - if vertex_resources.push_constant_buffers.len() > 1 { + let vertex_pcb = vertex_resources.resources_for_type(ResourceType::PushConstant)?; + if vertex_pcb.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one push constant buffer", )), )); } - for res in &vertex_resources.push_constant_buffers { - self.vertex.set_name(res.id, "LIBRA_PUSH_VERTEX_INSTANCE")?; + for res in vertex_pcb { self.vertex - .set_name(res.base_type_id, "LIBRA_PUSH_VERTEX")?; + .set_name(res.id, c"LIBRA_PUSH_VERTEX_INSTANCE")?; + self.vertex + .set_name(res.base_type_id, c"LIBRA_PUSH_VERTEX")?; } // todo: options let _flatten = false; - if vertex_resources.uniform_buffers.len() > 1 { + let vertex_ubo = vertex_resources.resources_for_type(ResourceType::UniformBuffer)?; + if vertex_ubo.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one uniform buffer", )), )); } - for res in &vertex_resources.uniform_buffers { + for res in vertex_ubo { // if flatten { // self.vertex.flatten_buffer_block(res.id)?; // } - self.vertex.set_name(res.id, "LIBRA_UBO_VERTEX_INSTANCE")?; - self.vertex.set_name(res.base_type_id, "LIBRA_UBO_VERTEX")?; + self.vertex.set_name(res.id, c"LIBRA_UBO_VERTEX_INSTANCE")?; self.vertex - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.vertex.unset_decoration(res.id, Decoration::Binding)?; + .set_name(res.base_type_id, c"LIBRA_UBO_VERTEX")?; + self.vertex.set_decoration( + res.id, + Decoration::DescriptorSet, + DecorationValue::unset(), + )?; + self.vertex + .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?; } - if fragment_resources.push_constant_buffers.len() > 1 { + let fragment_pcb = fragment_resources.resources_for_type(ResourceType::PushConstant)?; + if fragment_pcb.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one push constant buffer", )), )); } - for res in &fragment_resources.push_constant_buffers { + + for res in fragment_pcb { self.fragment - .set_name(res.id, "LIBRA_PUSH_FRAGMENT_INSTANCE")?; + .set_name(res.id, c"LIBRA_PUSH_FRAGMENT_INSTANCE")?; self.fragment - .set_name(res.base_type_id, "LIBRA_PUSH_FRAGMENT")?; + .set_name(res.base_type_id, c"LIBRA_PUSH_FRAGMENT")?; } - if fragment_resources.uniform_buffers.len() > 1 { + let fragment_ubo = fragment_resources.resources_for_type(ResourceType::UniformBuffer)?; + if fragment_ubo.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one uniform buffer", )), )); } - for res in &fragment_resources.uniform_buffers { + for res in fragment_ubo { // if flatten { // self.fragment.flatten_buffer_block(res.id)?; // } self.fragment - .set_name(res.id, "LIBRA_UBO_FRAGMENT_INSTANCE")?; + .set_name(res.id, c"LIBRA_UBO_FRAGMENT_INSTANCE")?; self.fragment - .set_name(res.base_type_id, "LIBRA_UBO_FRAGMENT")?; + .set_name(res.base_type_id, c"LIBRA_UBO_FRAGMENT")?; + self.fragment.set_decoration( + res.id, + Decoration::DescriptorSet, + DecorationValue::unset(), + )?; self.fragment - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.fragment - .unset_decoration(res.id, Decoration::Binding)?; + .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?; } let mut texture_fixups = Vec::new(); - for res in fragment_resources.sampled_images { - let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?; + + for res in fragment_resources.resources_for_type(ResourceType::SampledImage)? { + let Some(DecorationValue::Literal(binding)) = + self.fragment.decoration(res.id, Decoration::Binding)? + else { + continue; + }; + + self.fragment.set_decoration( + res.id, + Decoration::DescriptorSet, + DecorationValue::unset(), + )?; self.fragment - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.fragment - .unset_decoration(res.id, Decoration::Binding)?; - let mut name = res.name; + .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?; + let mut name = res.name.to_string(); name.push('\0'); texture_fixups.push((name, binding)); } + let vertex_compiled = self.vertex.compile(&options)?; + let fragment_compiled = self.fragment.compile(&options)?; + Ok(ShaderCompilerOutput { - vertex: self.vertex.compile()?, - fragment: self.fragment.compile()?, + vertex: vertex_compiled.to_string(), + fragment: fragment_compiled.to_string(), context: CrossGlslContext { sampler_bindings: texture_fixups, artifact: CompiledProgram { - vertex: CompiledAst(self.vertex), - fragment: CompiledAst(self.fragment), + vertex: vertex_compiled, + fragment: fragment_compiled, }, }, }) diff --git a/librashader-reflect/src/reflect/cross/hlsl.rs b/librashader-reflect/src/reflect/cross/hlsl.rs index f170ed3..9fddec9 100644 --- a/librashader-reflect/src/reflect/cross/hlsl.rs +++ b/librashader-reflect/src/reflect/cross/hlsl.rs @@ -2,14 +2,17 @@ use crate::back::hlsl::{CrossHlslContext, HlslBufferAssignment, HlslBufferAssign use crate::back::targets::HLSL; use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::error::ShaderCompileError; -use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; -use spirv_cross::hlsl::ShaderModel as HlslShaderModel; -use spirv_cross::spirv::Decoration; -use spirv_cross::ErrorCode; +use crate::reflect::cross::{CompiledProgram, CrossReflect}; +use spirv::Decoration; -pub(crate) type HlslReflect = CrossReflect; +use spirv_cross2::compile::hlsl::HlslShaderModel; +use spirv_cross2::compile::CompilableTarget; +use spirv_cross2::reflect::{DecorationValue, ResourceType}; +use spirv_cross2::{targets, SpirvCrossError}; -impl CompileShader for CrossReflect { +pub(crate) type HlslReflect = CrossReflect; + +impl CompileShader for CrossReflect { type Options = Option; type Context = CrossHlslContext; @@ -17,98 +20,107 @@ impl CompileShader for CrossReflect { mut self, options: Self::Options, ) -> Result, ShaderCompileError> { - let sm = options.unwrap_or(HlslShaderModel::V5_0); - let mut options = spirv_cross::hlsl::CompilerOptions::default(); - options.shader_model = sm; + let sm = options.unwrap_or(HlslShaderModel::ShaderModel5_0); - self.vertex.set_compiler_options(&options)?; - self.fragment.set_compiler_options(&options)?; + let mut options = targets::Hlsl::options(); + options.shader_model = sm; // todo: options - let vertex_resources = self.vertex.get_shader_resources()?; - let fragment_resources = self.fragment.get_shader_resources()?; + let vertex_resources = self.vertex.shader_resources()?; + let fragment_resources = self.fragment.shader_resources()?; let mut vertex_buffer_assignment = HlslBufferAssignments::default(); let mut fragment_buffer_assignment = HlslBufferAssignments::default(); - if vertex_resources.uniform_buffers.len() > 1 { + let mut vertex_ubo = vertex_resources.resources_for_type(ResourceType::UniformBuffer)?; + if vertex_ubo.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one uniform buffer", )), )); } - if let Some(buf) = vertex_resources.uniform_buffers.first() { + if let Some(buf) = vertex_ubo.next() { vertex_buffer_assignment.ubo = Some(HlslBufferAssignment { - name: buf.name.clone(), - id: buf.id, + name: buf.name.to_string(), + id: buf.id.id(), }) } - if vertex_resources.push_constant_buffers.len() > 1 { + let mut vertex_pcb = vertex_resources.resources_for_type(ResourceType::PushConstant)?; + if vertex_pcb.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one push constant buffer", )), )); } - - if let Some(buf) = vertex_resources.push_constant_buffers.first() { + if let Some(buf) = vertex_pcb.next() { vertex_buffer_assignment.push = Some(HlslBufferAssignment { - name: buf.name.clone(), - id: buf.id, + name: buf.name.to_string(), + id: buf.id.id(), }) } - if fragment_resources.uniform_buffers.len() > 1 { + let mut fragment_ubo = + fragment_resources.resources_for_type(ResourceType::UniformBuffer)?; + if fragment_ubo.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one uniform buffer", )), )); } - if let Some(buf) = fragment_resources.uniform_buffers.first() { + if let Some(buf) = fragment_ubo.next() { fragment_buffer_assignment.ubo = Some(HlslBufferAssignment { - name: buf.name.clone(), - id: buf.id, + name: buf.name.to_string(), + id: buf.id.id(), }) } - if fragment_resources.push_constant_buffers.len() > 1 { + let mut fragment_pcb = fragment_resources.resources_for_type(ResourceType::PushConstant)?; + if fragment_pcb.len() > 1 { return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( + SpirvCrossError::InvalidArgument(String::from( "Cannot have more than one push constant buffer", )), )); } - if let Some(buf) = fragment_resources.push_constant_buffers.first() { + if let Some(buf) = fragment_pcb.next() { fragment_buffer_assignment.push = Some(HlslBufferAssignment { - name: buf.name.clone(), - id: buf.id, + name: buf.name.to_string(), + id: buf.id.id(), }) } - if sm == HlslShaderModel::V3_0 { - for res in &fragment_resources.sampled_images { - let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?; + if sm == HlslShaderModel::ShaderModel3_0 { + for res in fragment_resources.resources_for_type(ResourceType::SampledImage)? { + let Some(DecorationValue::Literal(binding)) = + self.fragment.decoration(res.id, Decoration::Binding)? + else { + continue; + }; self.fragment - .set_name(res.id, &format!("LIBRA_SAMPLER2D_{binding}"))?; + .set_name(res.id, format!("LIBRA_SAMPLER2D_{binding}"))?; // self.fragment // .unset_decoration(res.id, Decoration::Binding)?; } } + let vertex_compiled = self.vertex.compile(&options)?; + let fragment_compiled = self.fragment.compile(&options)?; + Ok(ShaderCompilerOutput { - vertex: self.vertex.compile()?, - fragment: self.fragment.compile()?, + vertex: vertex_compiled.to_string(), + fragment: fragment_compiled.to_string(), context: CrossHlslContext { artifact: CompiledProgram { - vertex: CompiledAst(self.vertex), - fragment: CompiledAst(self.fragment), + vertex: vertex_compiled, + fragment: fragment_compiled, }, vertex_buffers: vertex_buffer_assignment, diff --git a/librashader-reflect/src/reflect/cross/mod.rs b/librashader-reflect/src/reflect/cross/mod.rs index a0214c4..d19da76 100644 --- a/librashader-reflect/src/reflect/cross/mod.rs +++ b/librashader-reflect/src/reflect/cross/mod.rs @@ -9,6 +9,7 @@ pub mod msl; use crate::error::{SemanticsErrorKind, ShaderReflectError}; use crate::front::SpirvCompilation; +use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData}; use crate::reflect::semantics::{ BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderReflection, ShaderSemantics, TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, @@ -16,13 +17,15 @@ use crate::reflect::semantics::{ MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, }; use crate::reflect::{align_uniform_size, ReflectShader}; -use std::fmt::Debug; -use std::ops::Deref; - -use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData}; use librashader_common::map::ShortString; -use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type}; -use spirv_cross::ErrorCode; +use spirv_cross2::compile::CompiledArtifact; +use spirv_cross2::reflect::{ + AllResources, BitWidth, DecorationValue, Resource, Scalar, ScalarKind, TypeInner, +}; +use spirv_cross2::spirv::Decoration; +use spirv_cross2::Compiler; +use spirv_cross2::Module; +use std::fmt::Debug; /// Reflect shaders under SPIRV-Cross semantics. /// @@ -30,135 +33,115 @@ use spirv_cross::ErrorCode; #[derive(Debug)] pub struct SpirvCross; -// This is "probably" OK. -unsafe impl Send for CrossReflect -where - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, -{ -} - +// todo: make this under a mutex pub(crate) struct CrossReflect where - T: spirv_cross::spirv::Target, - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, + T: spirv_cross2::compile::CompilableTarget, { - vertex: Ast, - fragment: Ast, -} - -///The output of the SPIR-V AST after compilation. -/// -/// This output is immutable and can not be recompiled later. -pub struct CompiledAst(Ast); -impl Deref for CompiledAst { - type Target = Ast; - - fn deref(&self) -> &Self::Target { - &self.0 - } + vertex: Compiler, + fragment: Compiler, } /// The compiled SPIR-V program after compilation. pub struct CompiledProgram where - T: spirv_cross::spirv::Target, + T: spirv_cross2::compile::CompilableTarget, { - pub vertex: CompiledAst, - pub fragment: CompiledAst, + pub vertex: CompiledArtifact, + pub fragment: CompiledArtifact, } -impl ValidateTypeSemantics for UniqueSemantics { - fn validate_type(&self, ty: &Type) -> Option { - let (Type::Float { - ref array, - vecsize, - columns, - .. - } - | Type::Int { - ref array, - vecsize, - columns, - .. - } - | Type::UInt { - ref array, - vecsize, - columns, - .. - }) = *ty +impl ValidateTypeSemantics> for UniqueSemantics { + fn validate_type(&self, ty: &TypeInner) -> Option { + let (TypeInner::Vector { .. } | TypeInner::Scalar { .. } | TypeInner::Matrix { .. }) = *ty else { return None; }; - if !array.is_empty() { - return None; - } - - let valid = match self { + match self { UniqueSemantics::MVP => { - matches!(ty, Type::Float { .. }) && vecsize == 4 && columns == 4 + if matches!(ty, TypeInner::Matrix { columns, rows, scalar: Scalar { size, .. } } if *columns == 4 + && *rows == 4 && *size == BitWidth::Word) + { + return Some(TypeInfo { + size: 4, + columns: 4, + }); + } } UniqueSemantics::FrameCount | UniqueSemantics::Rotation - | UniqueSemantics::TotalSubFrames - | UniqueSemantics::CurrentSubFrame => { - matches!(ty, Type::UInt { .. }) && vecsize == 1 && columns == 1 + | UniqueSemantics::CurrentSubFrame + | UniqueSemantics::TotalSubFrames => { + // Uint32 == width 4 + if matches!(ty, TypeInner::Scalar( Scalar { kind, size }) if *kind == ScalarKind::Uint && *size == BitWidth::Word) + { + return Some(TypeInfo { + size: 1, + columns: 1, + }); + } } UniqueSemantics::FrameDirection => { - matches!(ty, Type::Int { .. }) && vecsize == 1 && columns == 1 + // iint32 == width 4 + if matches!(ty, TypeInner::Scalar( Scalar { kind, size }) if *kind == ScalarKind::Int && *size == BitWidth::Word) + { + return Some(TypeInfo { + size: 1, + columns: 1, + }); + } } UniqueSemantics::FloatParameter => { - matches!(ty, Type::Float { .. }) && vecsize == 1 && columns == 1 + // Float32 == width 4 + if matches!(ty, TypeInner::Scalar( Scalar { kind, size }) if *kind == ScalarKind::Float && *size == BitWidth::Word) + { + return Some(TypeInfo { + size: 1, + columns: 1, + }); + } + } + _ => { + if matches!(ty, TypeInner::Vector { scalar: Scalar { size, kind }, width: vecwidth, .. } + if *kind == ScalarKind::Float && *size == BitWidth::Word && *vecwidth == 4) + { + return Some(TypeInfo { + size: 4, + columns: 1, + }); + } } - _ => matches!(ty, Type::Float { .. }) && vecsize == 4 && columns == 1, }; - if valid { - Some(TypeInfo { - size: vecsize, - columns, - }) - } else { - None - } + None } } -impl ValidateTypeSemantics for TextureSemantics { - fn validate_type(&self, ty: &Type) -> Option { - let Type::Float { - ref array, - vecsize, - columns, - .. - } = *ty +impl ValidateTypeSemantics> for TextureSemantics { + fn validate_type(&self, ty: &TypeInner) -> Option { + let TypeInner::Vector { + scalar: Scalar { size, kind }, + width: vecwidth, + } = ty else { return None; }; - if !array.is_empty() { - return None; + if *kind == ScalarKind::Float && *size == BitWidth::Word && *vecwidth == 4 { + return Some(TypeInfo { + size: 4, + columns: 1, + }); } - if vecsize == 4 && columns == 1 { - Some(TypeInfo { - size: vecsize, - columns, - }) - } else { - None - } + None } } impl TryFrom<&SpirvCompilation> for CrossReflect where - T: spirv_cross::spirv::Target, - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, + T: spirv_cross2::compile::CompilableTarget, { type Error = ShaderReflectError; @@ -166,8 +149,8 @@ where let vertex_module = Module::from_words(&value.vertex); let fragment_module = Module::from_words(&value.fragment); - let vertex = Ast::parse(&vertex_module)?; - let fragment = Ast::parse(&fragment_module)?; + let vertex = Compiler::new(vertex_module)?; + let fragment = Compiler::new(fragment_module)?; Ok(CrossReflect { vertex, fragment }) } @@ -175,14 +158,12 @@ where impl CrossReflect where - T: spirv_cross::spirv::Target, - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, + T: spirv_cross2::compile::CompilableTarget, { fn validate( &self, - vertex_res: &ShaderResources, - fragment_res: &ShaderResources, + vertex_res: &AllResources, + fragment_res: &AllResources, ) -> Result<(), ShaderReflectError> { if !vertex_res.sampled_images.is_empty() || !vertex_res.storage_buffers.is_empty() @@ -219,9 +200,15 @@ where )); } - let fragment_location = self + let Some(DecorationValue::Literal(fragment_location)) = self .fragment - .get_decoration(fragment_res.stage_outputs[0].id, Decoration::Location)?; + .decoration(fragment_res.stage_outputs[0].id, Decoration::Location)? + else { + return Err(ShaderReflectError::FragmentSemanticError( + SemanticsErrorKind::MissingBinding, + )); + }; + if fragment_location != 0 { return Err(ShaderReflectError::FragmentSemanticError( SemanticsErrorKind::InvalidLocation(fragment_location), @@ -229,15 +216,54 @@ where } // Ensure that vertex attributes use location 0 and 1 - let vert_mask = vertex_res.stage_inputs.iter().try_fold(0, |mask, input| { - Ok::( - mask | 1 << self.vertex.get_decoration(input.id, Decoration::Location)?, - ) - })?; - if vert_mask != 0x3 { - return Err(ShaderReflectError::VertexSemanticError( - SemanticsErrorKind::InvalidLocation(vert_mask), - )); + // Verify Vertex inputs + 'vertex: { + let entry_points = self.vertex.entry_points()?; + if entry_points.len() != 1 { + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::InvalidEntryPointCount(entry_points.len()), + )); + } + + let vert_inputs = vertex_res.stage_inputs.len(); + if vert_inputs != 2 { + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::InvalidInputCount(vert_inputs), + )); + } + + for input in &vertex_res.stage_inputs { + let location = self.vertex.decoration(input.id, Decoration::Location)?; + let Some(DecorationValue::Literal(location)) = location else { + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::MissingBinding, + )); + }; + + if location == 0 { + let pos_type = &self.vertex.type_description(input.base_type_id)?; + if !matches!(pos_type.inner, TypeInner::Vector { width, ..} if width == 4) { + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::InvalidLocation(location), + )); + } + break 'vertex; + } + + if location == 1 { + let coord_type = &self.vertex.type_description(input.base_type_id)?; + if !matches!(coord_type.inner, TypeInner::Vector { width, ..} if width == 2) { + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::InvalidLocation(location), + )); + } + break 'vertex; + } + + return Err(ShaderReflectError::VertexSemanticError( + SemanticsErrorKind::InvalidLocation(location), + )); + } } if vertex_res.uniform_buffers.len() > 1 { @@ -271,17 +297,27 @@ where impl CrossReflect where - T: spirv_cross::spirv::Target, - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, + T: spirv_cross2::compile::CompilableTarget, { fn get_ubo_data( - ast: &Ast, + ast: &Compiler, ubo: &Resource, blame: SemanticErrorBlame, ) -> Result { - let descriptor_set = ast.get_decoration(ubo.id, Decoration::DescriptorSet)?; - let binding = ast.get_decoration(ubo.id, Decoration::Binding)?; + let Some(descriptor_set) = ast + .decoration(ubo.id, Decoration::DescriptorSet)? + .and_then(|l| l.as_literal()) + else { + return Err(blame.error(SemanticsErrorKind::MissingBinding)); + }; + + let Some(binding) = ast + .decoration(ubo.id, Decoration::Binding)? + .and_then(|l| l.as_literal()) + else { + return Err(blame.error(SemanticsErrorKind::MissingBinding)); + }; + if binding >= MAX_BINDINGS_COUNT { return Err(blame.error(SemanticsErrorKind::InvalidBinding(binding))); } @@ -289,21 +325,19 @@ where return Err(blame.error(SemanticsErrorKind::InvalidDescriptorSet(descriptor_set))); } - let size = ast.get_declared_struct_size(ubo.base_type_id)?; - Ok(UboData { - // descriptor_set, - // id: ubo.id, - binding, - size, - }) + let size = ast.type_description(ubo.base_type_id)?.size_hint.declared() as u32; + Ok(UboData { binding, size }) } fn get_push_size( - ast: &Ast, + ast: &Compiler, push: &Resource, blame: SemanticErrorBlame, ) -> Result { - let size = ast.get_declared_struct_size(push.base_type_id)?; + let size = ast + .type_description(push.base_type_id)? + .size_hint + .declared() as u32; if size > MAX_PUSH_BUFFER_SIZE { return Err(blame.error(SemanticsErrorKind::InvalidPushBufferSize(size))); } @@ -311,7 +345,7 @@ where } fn reflect_buffer_range_metas( - ast: &Ast, + ast: &Compiler, resource: &Resource, pass_number: usize, semantics: &ShaderSemantics, @@ -319,24 +353,30 @@ where offset_type: UniformMemberBlock, blame: SemanticErrorBlame, ) -> Result<(), ShaderReflectError> { - let ranges = ast.get_active_buffer_ranges(resource.id)?; + let ranges = ast.active_buffer_ranges(resource.id)?; for range in ranges { - let name = ast.get_member_name(resource.base_type_id, range.index)?; - let ubo_type = ast.get_type(resource.base_type_id)?; - let range_type = match ubo_type { - Type::Struct { member_types, .. } => { - let range_type = member_types + let Some(name) = ast.member_name(resource.base_type_id, range.index)? else { + // member has no name! + return Err(blame.error(SemanticsErrorKind::InvalidRange(range.index))); + }; + + let ubo_type = ast.type_description(resource.base_type_id)?; + let range_type = match ubo_type.inner { + TypeInner::Struct(struct_def) => { + let range_type = struct_def + .members .get(range.index as usize) - .cloned() .ok_or(blame.error(SemanticsErrorKind::InvalidRange(range.index)))?; - ast.get_type(range_type)? + ast.type_description(range_type.id)? } _ => return Err(blame.error(SemanticsErrorKind::InvalidResourceType)), }; - if let Some(parameter) = semantics.uniform_semantics.get_unique_semantic(&name) { - let Some(typeinfo) = parameter.semantics.validate_type(&range_type) else { - return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name))); + if let Some(parameter) = semantics.uniform_semantics.unique_semantic(&name) { + let Some(typeinfo) = parameter.semantics.validate_type(&range_type.inner) else { + return Err( + blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name.to_string())) + ); }; match ¶meter.semantics { @@ -347,7 +387,7 @@ where && expected != offset { return Err(ShaderReflectError::MismatchedOffset { - semantic: name, + semantic: name.to_string(), expected, received: offset, ty: offset_type, @@ -356,7 +396,7 @@ where } if meta.size != typeinfo.size { return Err(ShaderReflectError::MismatchedSize { - semantic: name, + semantic: name.to_string(), vertex: meta.size, fragment: typeinfo.size, pass: pass_number, @@ -365,7 +405,7 @@ where *meta.offset.offset_mut(offset_type) = Some(offset); } else { - let name = ShortString::from(name); + let name = ShortString::from(name.as_ref()); meta.parameter_meta.insert( name.clone(), VariableMeta { @@ -383,7 +423,7 @@ where && expected != offset { return Err(ShaderReflectError::MismatchedOffset { - semantic: name, + semantic: name.to_string(), expected, received: offset, ty: offset_type, @@ -392,7 +432,7 @@ where } if meta.size != typeinfo.size * typeinfo.columns { return Err(ShaderReflectError::MismatchedSize { - semantic: name, + semantic: name.to_string(), vertex: meta.size, fragment: typeinfo.size, pass: pass_number, @@ -404,7 +444,7 @@ where meta.unique_meta.insert( *semantics, VariableMeta { - id: name.into(), + id: ShortString::from(name.as_ref()), offset: MemberOffset::new(offset, offset_type), size: typeinfo.size * typeinfo.columns, }, @@ -412,9 +452,11 @@ where } } } - } else if let Some(texture) = semantics.uniform_semantics.get_texture_semantic(&name) { - let Some(_typeinfo) = texture.semantics.validate_type(&range_type) else { - return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name))); + } else if let Some(texture) = semantics.uniform_semantics.texture_semantic(&name) { + let Some(_typeinfo) = texture.semantics.validate_type(&range_type.inner) else { + return Err( + blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name.to_string())) + ); }; if let TextureSemantics::PassOutput = texture.semantics { @@ -432,7 +474,7 @@ where && expected != offset { return Err(ShaderReflectError::MismatchedOffset { - semantic: name, + semantic: name.to_string(), expected, received: offset, ty: offset_type, @@ -455,12 +497,12 @@ where SemanticErrorBlame::Vertex => BindingStage::VERTEX, SemanticErrorBlame::Fragment => BindingStage::FRAGMENT, }, - id: ShortString::from(name), + id: ShortString::from(name.as_ref()), }, ); } } else { - return Err(blame.error(SemanticsErrorKind::UnknownSemantics(name))); + return Err(blame.error(SemanticsErrorKind::UnknownSemantics(name.to_string()))); } } Ok(()) @@ -473,12 +515,12 @@ where ) -> Result>, ShaderReflectError> { if let Some(vertex_ubo) = vertex_ubo { self.vertex - .set_decoration(vertex_ubo.id, Decoration::Binding, 0)?; + .set_decoration(vertex_ubo.id, Decoration::Binding, Some(0))?; } if let Some(fragment_ubo) = fragment_ubo { self.fragment - .set_decoration(fragment_ubo.id, Decoration::Binding, 0)?; + .set_decoration(fragment_ubo.id, Decoration::Binding, Some(0))?; } match (vertex_ubo, fragment_ubo) { @@ -530,10 +572,7 @@ where semantics: &ShaderSemantics, meta: &mut BindingMeta, ) -> Result<(), ShaderReflectError> { - let Some(semantic) = semantics - .texture_semantics - .get_texture_semantic(texture.name) - else { + let Some(semantic) = semantics.texture_semantics.texture_semantic(texture.name) else { return Err( SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics( texture.name.to_string(), @@ -561,12 +600,25 @@ where &'a self, texture: &'a Resource, ) -> Result, ShaderReflectError> { - let descriptor_set = self + let Some(descriptor_set) = self .fragment - .get_decoration(texture.id, Decoration::DescriptorSet)?; - let binding = self + .decoration(texture.id, Decoration::DescriptorSet)? + .and_then(|l| l.as_literal()) + else { + return Err(ShaderReflectError::FragmentSemanticError( + SemanticsErrorKind::MissingBinding, + )); + }; + let Some(binding) = self .fragment - .get_decoration(texture.id, Decoration::Binding)?; + .decoration(texture.id, Decoration::Binding)? + .and_then(|l| l.as_literal()) + else { + return Err(ShaderReflectError::FragmentSemanticError( + SemanticsErrorKind::MissingBinding, + )); + }; + if descriptor_set != 0 { return Err(ShaderReflectError::FragmentSemanticError( SemanticsErrorKind::InvalidDescriptorSet(descriptor_set), @@ -593,12 +645,12 @@ where ) -> Result>>, ShaderReflectError> { if let Some(vertex_pcb) = vertex_pcb { self.vertex - .set_decoration(vertex_pcb.id, Decoration::Binding, 1)?; + .set_decoration(vertex_pcb.id, Decoration::Binding, Some(1))?; } if let Some(fragment_pcb) = fragment_pcb { self.fragment - .set_decoration(fragment_pcb.id, Decoration::Binding, 1)?; + .set_decoration(fragment_pcb.id, Decoration::Binding, Some(1))?; } match (vertex_pcb, fragment_pcb) { @@ -647,17 +699,15 @@ where impl ReflectShader for CrossReflect where - T: spirv_cross::spirv::Target, - Ast: spirv_cross::spirv::Compile, - Ast: spirv_cross::spirv::Parse, + T: spirv_cross2::compile::CompilableTarget, { fn reflect( &mut self, pass_number: usize, semantics: &ShaderSemantics, ) -> Result { - let vertex_res = self.vertex.get_shader_resources()?; - let fragment_res = self.fragment.get_shader_resources()?; + let vertex_res = self.vertex.shader_resources()?.all_resources()?; + let fragment_res = self.fragment.shader_resources()?.all_resources()?; self.validate(&vertex_res, &fragment_res)?; let vertex_ubo = vertex_res.uniform_buffers.first(); diff --git a/librashader-reflect/src/reflect/cross/msl.rs b/librashader-reflect/src/reflect/cross/msl.rs index 6c07497..131f3a2 100644 --- a/librashader-reflect/src/reflect/cross/msl.rs +++ b/librashader-reflect/src/reflect/cross/msl.rs @@ -2,99 +2,101 @@ use crate::back::msl::CrossMslContext; use crate::back::targets::MSL; use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::error::ShaderCompileError; -use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; -use spirv_cross::msl; -use spirv_cross::msl::{ResourceBinding, ResourceBindingLocation}; -use spirv_cross::spirv::{Ast, Decoration, ExecutionModel}; -use std::collections::BTreeMap; +use crate::reflect::cross::{CompiledProgram, CrossReflect}; -pub(crate) type MslReflect = CrossReflect; +use spirv::Decoration; +use spirv_cross2::compile::msl::{BindTarget, ResourceBinding}; +use spirv_cross2::compile::{msl, CompilableTarget}; +use spirv_cross2::reflect::{DecorationValue, ResourceType}; +use spirv_cross2::{targets, Compiler}; -impl CompileShader for CrossReflect { - type Options = Option; +pub(crate) type MslReflect = CrossReflect; + +impl CompileShader for CrossReflect { + type Options = Option; type Context = CrossMslContext; fn compile( mut self, options: Self::Options, ) -> Result, ShaderCompileError> { - let version = options.unwrap_or(msl::Version::V2_0); - let mut vert_options = spirv_cross::msl::CompilerOptions::default(); - let mut frag_options = spirv_cross::msl::CompilerOptions::default(); - - vert_options.version = version; - frag_options.version = version; + let version = options.unwrap_or(msl::MslVersion::new(2, 0, 0)); + let mut options = targets::Msl::options(); + options.version = version; fn set_bindings( - ast: &Ast, - stage: ExecutionModel, - binding_map: &mut BTreeMap, + ast: &mut Compiler, + stage: spirv::ExecutionModel, ) -> Result<(), ShaderCompileError> { - let resources = ast.get_shader_resources()?; - for resource in &resources.push_constant_buffers { - let location = ResourceBindingLocation { - stage, - desc_set: msl::PUSH_CONSTANT_DESCRIPTOR_SET, - binding: msl::PUSH_CONSTANT_BINDING, - }; - let overridden = ResourceBinding { - buffer_id: ast.get_decoration(resource.id, Decoration::Binding)?, - texture_id: 0, - sampler_id: 0, - base_type: None, - count: 0, // no arrays allowed in slang shaders, otherwise we'd have to get the type and get the array length + let resources = ast.shader_resources()?; + for resource in resources.resources_for_type(ResourceType::PushConstant)? { + let Some(DecorationValue::Literal(buffer)) = + ast.decoration(resource.id, Decoration::Binding)? + else { + continue; }; - binding_map.insert(location, overridden); + ast.add_resource_binding( + stage, + ResourceBinding::PushConstantBuffer, + &BindTarget { + buffer, + texture: 0, + sampler: 0, + count: None, + }, + )? } - for resource in resources - .uniform_buffers - .iter() - .chain(resources.sampled_images.iter()) - { - let binding = ast.get_decoration(resource.id, Decoration::Binding)?; - let location = ResourceBindingLocation { + let ubos = resources.resources_for_type(ResourceType::UniformBuffer)?; + let sampled = resources.resources_for_type(ResourceType::SampledImage)?; + + for resource in ubos.chain(sampled) { + let Some(DecorationValue::Literal(binding)) = + ast.decoration(resource.id, Decoration::Binding)? + else { + continue; + }; + + let Some(DecorationValue::Literal(desc_set)) = + ast.decoration(resource.id, Decoration::DescriptorSet)? + else { + continue; + }; + + let overridden = BindTarget { + buffer: binding, + texture: binding, + sampler: binding, + count: None, + }; + + ast.add_resource_binding( stage, - desc_set: ast.get_decoration(resource.id, Decoration::DescriptorSet)?, - binding, - }; - - let overridden = ResourceBinding { - buffer_id: binding, - texture_id: binding, - sampler_id: binding, - base_type: None, - count: 0, // no arrays allowed in slang shaders, otherwise we'd have to get the type and get the array length - }; - - binding_map.insert(location, overridden); + ResourceBinding::Qualified { + set: desc_set, + binding, + }, + &overridden, + )? } Ok(()) } - set_bindings( - &self.vertex, - ExecutionModel::Vertex, - &mut vert_options.resource_binding_overrides, - )?; + set_bindings(&mut self.vertex, spirv::ExecutionModel::Vertex)?; - set_bindings( - &self.fragment, - ExecutionModel::Fragment, - &mut frag_options.resource_binding_overrides, - )?; + set_bindings(&mut self.fragment, spirv::ExecutionModel::Fragment)?; - self.vertex.set_compiler_options(&vert_options)?; - self.fragment.set_compiler_options(&frag_options)?; + let vertex_compiled = self.vertex.compile(&options)?; + let fragment_compiled = self.fragment.compile(&options)?; Ok(ShaderCompilerOutput { - vertex: self.vertex.compile()?, - fragment: self.fragment.compile()?, + vertex: vertex_compiled.to_string(), + fragment: fragment_compiled.to_string(), context: CrossMslContext { artifact: CompiledProgram { - vertex: CompiledAst(self.vertex), - fragment: CompiledAst(self.fragment), + vertex: vertex_compiled, + fragment: fragment_compiled, }, }, }) @@ -106,15 +108,13 @@ mod test { use crate::back::targets::{MSL, WGSL}; use crate::back::{CompileShader, FromCompilation}; use crate::reflect::cross::SpirvCross; - use crate::reflect::naga::{Naga, NagaLoweringOptions}; use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics}; use crate::reflect::ReflectShader; use bitflags::Flags; use librashader_common::map::{FastHashMap, ShortString}; use librashader_preprocess::ShaderSource; - use rustc_hash::FxHashMap; - use spirv_cross::msl; - use std::io::Write; + + use spirv_cross2::compile::msl::MslVersion; #[test] pub fn test_into() { @@ -148,7 +148,7 @@ mod test { ) .expect(""); - let compiled = msl.compile(Some(msl::Version::V2_0)).unwrap(); + let compiled = msl.compile(Some(MslVersion::new(2, 0, 0))).unwrap(); println!("{}", compiled.vertex); } diff --git a/librashader-reflect/src/reflect/naga/mod.rs b/librashader-reflect/src/reflect/naga/mod.rs index cf9bf86..273c0fa 100644 --- a/librashader-reflect/src/reflect/naga/mod.rs +++ b/librashader-reflect/src/reflect/naga/mod.rs @@ -212,7 +212,7 @@ impl ValidateTypeSemantics<&TypeInner> for UniqueSemantics { } }; - return None; + None } } @@ -566,7 +566,7 @@ impl NagaReflect { }; let &Some(Binding::Location { location, .. }) = &frag_output.binding else { - return Err(ShaderReflectError::VertexSemanticError( + return Err(ShaderReflectError::FragmentSemanticError( SemanticsErrorKind::MissingBinding, )); }; @@ -845,10 +845,7 @@ impl NagaReflect { semantics: &ShaderSemantics, meta: &mut BindingMeta, ) -> Result<(), ShaderReflectError> { - let Some(semantic) = semantics - .texture_semantics - .texture_semantic(texture.name) - else { + let Some(semantic) = semantics.texture_semantics.texture_semantic(texture.name) else { return Err( SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics( texture.name.to_string(), diff --git a/librashader-reflect/src/reflect/naga/msl.rs b/librashader-reflect/src/reflect/naga/msl.rs index 6794831..dfc110c 100644 --- a/librashader-reflect/src/reflect/naga/msl.rs +++ b/librashader-reflect/src/reflect/naga/msl.rs @@ -8,19 +8,9 @@ use naga::back::msl::{ }; use naga::valid::{Capabilities, ValidationFlags}; use naga::{Module, TypeInner}; -use spirv_cross::msl::Version; fn msl_version_to_naga_msl(version: MslVersion) -> (u8, u8) { - match version { - Version::V1_0 => (1, 0), - Version::V1_1 => (1, 1), - Version::V1_2 => (1, 2), - Version::V2_0 => (2, 0), - Version::V2_1 => (2, 1), - Version::V2_2 => (2, 2), - Version::V2_3 => (2, 3), - _ => (0, 0), - } + (version.major as u8, version.minor as u8) } impl CompileShader for NagaReflect { @@ -33,7 +23,7 @@ impl CompileShader for NagaReflect { ) -> Result, ShaderCompileError> { // https://github.com/libretro/RetroArch/blob/434e94c782af2e4d4277a24b7ed8e5fc54870088/gfx/drivers_shader/slang_process.cpp#L524 - let lang_version = msl_version_to_naga_msl(options.unwrap_or(MslVersion::V2_0)); + let lang_version = msl_version_to_naga_msl(options.unwrap_or(MslVersion::new(2, 0, 0))); let mut vert_options = Options { lang_version, diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 61e3a44..dce34b1 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -550,7 +550,7 @@ impl FilterChainD3D12 { } else { let hlsl_reflection = hlsl.reflect(index, semantics)?; let hlsl = hlsl.compile(Some( - librashader_reflect::back::hlsl::HlslShaderModel::V6_0, + librashader_reflect::back::hlsl::HlslShaderModel::ShaderModel6_0, ))?; let graphics_pipeline = D3D12GraphicsPipeline::new_from_hlsl( diff --git a/librashader-runtime-d3d9/src/filter_chain.rs b/librashader-runtime-d3d9/src/filter_chain.rs index cdaa61b..8e091b7 100644 --- a/librashader-runtime-d3d9/src/filter_chain.rs +++ b/librashader-runtime-d3d9/src/filter_chain.rs @@ -96,7 +96,7 @@ impl FilterChainD3D9 { ) -> error::Result> { let builder_fn = |(index, (config, source, mut reflect)): (usize, ShaderPassMeta)| { let mut reflection = reflect.reflect(index, semantics)?; - let hlsl = reflect.compile(Some(HlslShaderModel::V3_0))?; + let hlsl = reflect.compile(Some(HlslShaderModel::ShaderModel3_0))?; // eprintln!("===vs===\n{}", hlsl.vertex); diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index 4442977..d491c8a 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -19,7 +19,7 @@ librashader-reflect = { path = "../librashader-reflect", version = "0.3.3" } librashader-runtime = { path = "../librashader-runtime" , version = "0.3.3" } librashader-cache = { path = "../librashader-cache", version = "0.3.3" } -spirv_cross = { workspace = true } +spirv-cross2 = { workspace = true, features = ["glsl"] } gl = "0.14.0" bytemuck = { version = "1.12.3", features = ["derive"] } thiserror = "1.0.37" diff --git a/librashader-runtime-gl/src/error.rs b/librashader-runtime-gl/src/error.rs index 53fc0da..1b6da96 100644 --- a/librashader-runtime-gl/src/error.rs +++ b/librashader-runtime-gl/src/error.rs @@ -13,7 +13,7 @@ pub enum FilterChainError { #[error("fbo initialization error")] FramebufferInit(GLenum), #[error("SPIRV reflection error")] - SpirvCrossReflectError(#[from] spirv_cross::ErrorCode), + SpirvCrossReflectError(#[from] spirv_cross2::SpirvCrossError), #[error("shader preset parse error")] ShaderPresetError(#[from] ParsePresetError), #[error("shader preprocess error")] diff --git a/librashader-runtime-gl/src/gl/gl3/compile_program.rs b/librashader-runtime-gl/src/gl/gl3/compile_program.rs index 9477599..abb7aa0 100644 --- a/librashader-runtime-gl/src/gl/gl3/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl3/compile_program.rs @@ -5,7 +5,8 @@ use crate::util; use gl::types::{GLint, GLuint}; use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; -use spirv_cross::spirv::Decoration; +use spirv_cross2::reflect::ResourceType; +use spirv_cross2::spirv::Decoration; pub struct Gl3CompileProgram; @@ -14,7 +15,7 @@ impl CompileProgram for Gl3CompileProgram { glsl: ShaderCompilerOutput, _cache: bool, ) -> crate::error::Result<(GLuint, UniformLocation)> { - let vertex_resources = glsl.context.artifact.vertex.get_shader_resources()?; + let vertex_resources = glsl.context.artifact.vertex.shader_resources()?; let (program, ubo_location) = unsafe { let vertex = util::gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str())?; @@ -24,13 +25,18 @@ impl CompileProgram for Gl3CompileProgram { gl::AttachShader(program, vertex); gl::AttachShader(program, fragment); - for res in vertex_resources.stage_inputs { - let loc = glsl + for res in vertex_resources.resources_for_type(ResourceType::StageInput)? { + let Some(loc) = glsl .context .artifact .vertex - .get_decoration(res.id, Decoration::Location)?; - let mut name = res.name; + .decoration(res.id, Decoration::Location)? + .and_then(|d| d.as_literal()) + else { + continue; + }; + + let mut name = res.name.to_string(); name.push('\0'); gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) diff --git a/librashader-runtime-gl/src/gl/gl46/compile_program.rs b/librashader-runtime-gl/src/gl/gl46/compile_program.rs index 5595dd7..b058331 100644 --- a/librashader-runtime-gl/src/gl/gl46/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl46/compile_program.rs @@ -6,7 +6,8 @@ use gl::types::{GLint, GLsizei, GLuint}; use librashader_cache::Cacheable; use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; -use spirv_cross::spirv::Decoration; +use spirv_cross2::reflect::ResourceType; +use spirv_cross2::spirv::Decoration; pub struct Gl4CompileProgram; @@ -45,7 +46,7 @@ impl CompileProgram for Gl4CompileProgram { glsl: ShaderCompilerOutput, cache: bool, ) -> crate::error::Result<(GLuint, UniformLocation)> { - let vertex_resources = glsl.context.artifact.vertex.get_shader_resources()?; + let vertex_resources = glsl.context.artifact.vertex.shader_resources()?; let program = librashader_cache::cache_shader_object( "opengl4", @@ -58,13 +59,18 @@ impl CompileProgram for Gl4CompileProgram { gl::AttachShader(program, vertex); gl::AttachShader(program, fragment); - for res in &vertex_resources.stage_inputs { - let loc = glsl + for res in vertex_resources.resources_for_type(ResourceType::StageInput)? { + let Some(loc) = glsl .context .artifact .vertex - .get_decoration(res.id, Decoration::Location)?; - let mut name = res.name.clone(); + .decoration(res.id, Decoration::Location)? + .and_then(|d| d.as_literal()) + else { + continue; + }; + + let mut name = res.name.to_string(); name.push('\0'); gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index 5179118..204a613 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -36,40 +36,40 @@ pub fn gl_get_version() -> GlslVersion { match maj_ver { 3 => match min_ver { - 3 => GlslVersion::V3_30, - 2 => GlslVersion::V1_50, - 1 => GlslVersion::V1_40, - 0 => GlslVersion::V1_30, - _ => GlslVersion::V1_50, + 3 => GlslVersion::Glsl330, + 2 => GlslVersion::Glsl150, + 1 => GlslVersion::Glsl140, + 0 => GlslVersion::Glsl130, + _ => GlslVersion::Glsl150, }, 4 => match min_ver { - 6 => GlslVersion::V4_60, - 5 => GlslVersion::V4_50, - 4 => GlslVersion::V4_40, - 3 => GlslVersion::V4_30, - 2 => GlslVersion::V4_20, - 1 => GlslVersion::V4_10, - 0 => GlslVersion::V4_00, - _ => GlslVersion::V1_50, + 6 => GlslVersion::Glsl460, + 5 => GlslVersion::Glsl450, + 4 => GlslVersion::Glsl440, + 3 => GlslVersion::Glsl430, + 2 => GlslVersion::Glsl420, + 1 => GlslVersion::Glsl410, + 0 => GlslVersion::Glsl400, + _ => GlslVersion::Glsl150, }, - _ => GlslVersion::V1_50, + _ => GlslVersion::Glsl150, } } pub fn gl_u16_to_version(version: u16) -> GlslVersion { match version { 0 => gl_get_version(), - 300 => GlslVersion::V1_30, - 310 => GlslVersion::V1_40, - 320 => GlslVersion::V1_50, - 330 => GlslVersion::V3_30, - 400 => GlslVersion::V4_00, - 410 => GlslVersion::V4_10, - 420 => GlslVersion::V4_20, - 430 => GlslVersion::V4_30, - 440 => GlslVersion::V4_40, - 450 => GlslVersion::V4_50, - 460 => GlslVersion::V4_60, - _ => GlslVersion::V1_50, + 300 => GlslVersion::Glsl130, + 310 => GlslVersion::Glsl140, + 320 => GlslVersion::Glsl150, + 330 => GlslVersion::Glsl330, + 400 => GlslVersion::Glsl400, + 410 => GlslVersion::Glsl410, + 420 => GlslVersion::Glsl420, + 430 => GlslVersion::Glsl430, + 440 => GlslVersion::Glsl440, + 450 => GlslVersion::Glsl450, + 460 => GlslVersion::Glsl460, + _ => GlslVersion::Glsl150, } } diff --git a/librashader-runtime-mtl/src/filter_chain.rs b/librashader-runtime-mtl/src/filter_chain.rs index d7a944d..2137994 100644 --- a/librashader-runtime-mtl/src/filter_chain.rs +++ b/librashader-runtime-mtl/src/filter_chain.rs @@ -154,7 +154,7 @@ impl FilterChainMetal { .enumerate() .map(|(index, (config, source, mut reflect))| { let reflection = reflect.reflect(index, semantics)?; - let msl = reflect.compile(Some(MslVersion::V2_0))?; + let msl = reflect.compile(Some(MslVersion::new(2, 0, 0)))?; let ubo_size = reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize); let push_size = reflection diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 1f7c227..5cc09d7 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -190,8 +190,6 @@ pub mod reflect { pub use librashader_reflect::back::msl::CrossMslContext; - pub use librashader_reflect::reflect::cross::CompiledAst; - pub use librashader_reflect::reflect::cross::CompiledProgram; }