From c67e9f48013e7c26dd5053b31576ca2d9cef0b63 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sun, 11 Feb 2024 02:23:01 -0500 Subject: [PATCH] reflect: move folder structure around to be a little better --- librashader-reflect/Cargo.toml | 13 +- librashader-reflect/src/back/dxil.rs | 3 +- .../src/back/{cross.rs => glsl.rs} | 27 +-- librashader-reflect/src/back/hlsl.rs | 30 +++ librashader-reflect/src/back/mod.rs | 7 +- librashader-reflect/src/back/msl.rs | 52 +++++ librashader-reflect/src/back/spirv.rs | 32 +++- librashader-reflect/src/back/wgsl.rs | 117 +----------- librashader-reflect/src/error.rs | 8 +- librashader-reflect/src/reflect/cross/glsl.rs | 142 ++++++++++++++ librashader-reflect/src/reflect/cross/hlsl.rs | 36 ++++ .../src/reflect/{cross.rs => cross/mod.rs} | 178 +----------------- librashader-reflect/src/reflect/cross/msl.rs | 39 ++++ librashader-reflect/src/reflect/naga/mod.rs | 83 +++++++- librashader-reflect/src/reflect/naga/msl.rs | 16 ++ librashader-reflect/src/reflect/naga/spirv.rs | 54 ++++++ librashader-reflect/src/reflect/naga/wgsl.rs | 40 ++++ .../src/graphics_pipeline.rs | 2 +- .../src/filter_chain/filter_impl.rs | 2 +- .../src/gl/gl3/compile_program.rs | 2 +- .../src/gl/gl46/compile_program.rs | 2 +- librashader-runtime-gl/src/gl/mod.rs | 2 +- librashader-runtime-gl/src/util.rs | 2 +- librashader-runtime-wgpu/src/filter_chain.rs | 4 +- librashader/src/lib.rs | 8 +- 25 files changed, 570 insertions(+), 331 deletions(-) rename librashader-reflect/src/back/{cross.rs => glsl.rs} (58%) create mode 100644 librashader-reflect/src/back/hlsl.rs create mode 100644 librashader-reflect/src/reflect/cross/glsl.rs create mode 100644 librashader-reflect/src/reflect/cross/hlsl.rs rename librashader-reflect/src/reflect/{cross.rs => cross/mod.rs} (80%) create mode 100644 librashader-reflect/src/reflect/cross/msl.rs create mode 100644 librashader-reflect/src/reflect/naga/msl.rs create mode 100644 librashader-reflect/src/reflect/naga/spirv.rs create mode 100644 librashader-reflect/src/reflect/naga/wgsl.rs diff --git a/librashader-reflect/Cargo.toml b/librashader-reflect/Cargo.toml index bb13e23..d9cadbf 100644 --- a/librashader-reflect/Cargo.toml +++ b/librashader-reflect/Cargo.toml @@ -25,7 +25,7 @@ librashader-presets = { path = "../librashader-presets", version = "0.2.0-beta.9 spirv_cross = { package = "librashader-spirv-cross", version = "0.23", optional = true } -naga = { version = "0.19.0", features = ["spv-in", "wgsl-out"], optional = true } +naga = { version = "0.19.0", features = ["spv-in", "spv-out"], optional = true } rspirv = { version = "0.12.0", optional = true } spirv = { version = "0.3.0", optional = true} @@ -39,9 +39,10 @@ version = "0.4" optional = true [features] -default = ["cross", "wgsl", "serialize"] -dxil = ["cross", "spirv-to-dxil"] -wgsl = ["cross", "naga", "spirv", "rspirv"] -cross = [ "spirv_cross", "spirv_cross/glsl", "spirv_cross/hlsl" ] +default = ["cross", "naga", "serialize"] +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 = [ "wgsl" ] serialize = [ "serde" ] -msl = [ "cross", "naga" ] \ No newline at end of file +msl = [ "spirv_cross/msl", "naga/msl-out" ] \ No newline at end of file diff --git a/librashader-reflect/src/back/dxil.rs b/librashader-reflect/src/back/dxil.rs index cf00a78..8dd1c76 100644 --- a/librashader-reflect/src/back/dxil.rs +++ b/librashader-reflect/src/back/dxil.rs @@ -9,7 +9,8 @@ use spirv_to_dxil::{ use crate::back::targets::{OutputTarget, DXIL}; use crate::error::{ShaderCompileError, ShaderReflectError}; use crate::front::SpirvCompilation; -use crate::reflect::cross::{GlslReflect, SpirvCross}; +use crate::reflect::cross::glsl::GlslReflect; +use crate::reflect::cross::SpirvCross; use crate::reflect::ReflectShader; impl OutputTarget for DXIL { diff --git a/librashader-reflect/src/back/cross.rs b/librashader-reflect/src/back/glsl.rs similarity index 58% rename from librashader-reflect/src/back/cross.rs rename to librashader-reflect/src/back/glsl.rs index 94cb82a..8f454c6 100644 --- a/librashader-reflect/src/back/cross.rs +++ b/librashader-reflect/src/back/glsl.rs @@ -1,13 +1,14 @@ -use crate::back::targets::{GLSL, HLSL}; +use crate::back::targets::GLSL; use crate::back::{CompileShader, CompilerBackend, FromCompilation}; use crate::error::ShaderReflectError; use crate::front::SpirvCompilation; -use crate::reflect::cross::{CompiledProgram, GlslReflect, HlslReflect, SpirvCross}; +use crate::reflect::cross::{CompiledProgram, SpirvCross}; use crate::reflect::ReflectShader; /// The GLSL version to target. pub use spirv_cross::glsl::Version as GlslVersion; +use crate::reflect::cross::glsl::GlslReflect; /// The HLSL shader model version to target. pub use spirv_cross::hlsl::ShaderModel as HlslShaderModel; @@ -34,25 +35,3 @@ impl FromCompilation for GLSL { }) } } - -/// The context for a HLSL compilation via spirv-cross. -pub struct CrossHlslContext { - /// The compiled HLSL program. - pub artifact: CompiledProgram, -} - -impl FromCompilation for HLSL { - type Target = HLSL; - type Options = Option; - type Context = CrossHlslContext; - type Output = impl CompileShader - + ReflectShader; - - fn from_compilation( - compile: SpirvCompilation, - ) -> Result, ShaderReflectError> { - Ok(CompilerBackend { - backend: HlslReflect::try_from(&compile)?, - }) - } -} diff --git a/librashader-reflect/src/back/hlsl.rs b/librashader-reflect/src/back/hlsl.rs new file mode 100644 index 0000000..da5773b --- /dev/null +++ b/librashader-reflect/src/back/hlsl.rs @@ -0,0 +1,30 @@ +use crate::back::targets::HLSL; +use crate::back::{CompileShader, CompilerBackend, FromCompilation}; +use crate::error::ShaderReflectError; +use crate::front::SpirvCompilation; +use crate::reflect::cross::hlsl::HlslReflect; +use crate::reflect::cross::{CompiledProgram, SpirvCross}; +use crate::reflect::ReflectShader; +use spirv_cross::hlsl::ShaderModel as HlslShaderModel; + +/// The context for a HLSL compilation via spirv-cross. +pub struct CrossHlslContext { + /// The compiled HLSL program. + pub artifact: CompiledProgram, +} + +impl FromCompilation for HLSL { + type Target = HLSL; + type Options = Option; + type Context = CrossHlslContext; + type Output = impl CompileShader + + ReflectShader; + + fn from_compilation( + compile: SpirvCompilation, + ) -> Result, ShaderReflectError> { + Ok(CompilerBackend { + backend: HlslReflect::try_from(&compile)?, + }) + } +} diff --git a/librashader-reflect/src/back/mod.rs b/librashader-reflect/src/back/mod.rs index bb685b6..4aba7e0 100644 --- a/librashader-reflect/src/back/mod.rs +++ b/librashader-reflect/src/back/mod.rs @@ -1,8 +1,9 @@ -pub mod cross; #[cfg(all(target_os = "windows", feature = "dxil"))] pub mod dxil; -mod msl; -mod spirv; +pub mod glsl; +pub mod hlsl; +pub mod msl; +pub mod spirv; pub mod targets; pub mod wgsl; diff --git a/librashader-reflect/src/back/msl.rs b/librashader-reflect/src/back/msl.rs index 8b13789..8003c55 100644 --- a/librashader-reflect/src/back/msl.rs +++ b/librashader-reflect/src/back/msl.rs @@ -1 +1,53 @@ +use crate::back::targets::MSL; +use crate::back::{CompileShader, CompilerBackend, FromCompilation}; +use crate::error::ShaderReflectError; +use crate::front::SpirvCompilation; +use crate::reflect::cross::msl::MslReflect; +use crate::reflect::cross::{CompiledProgram, SpirvCross}; +use crate::reflect::naga::{Naga, NagaReflect}; +use crate::reflect::ReflectShader; +/// Compiler options for MSL +#[derive(Debug, Default, Clone)] +pub struct MslNagaCompileOptions { + // pub write_pcb_as_ubo: bool, + pub sampler_bind_group: u32, +} + +/// The context for a MSL compilation via spirv-cross. +pub struct CrossMslContext { + /// The compiled HLSL program. + pub artifact: CompiledProgram, +} + +impl FromCompilation for MSL { + type Target = MSL; + type Options = Option; + type Context = CrossMslContext; + type Output = impl CompileShader + + ReflectShader; + + fn from_compilation( + compile: SpirvCompilation, + ) -> Result, ShaderReflectError> { + Ok(CompilerBackend { + backend: MslReflect::try_from(&compile)?, + }) + } +} + +impl FromCompilation for MSL { + type Target = MSL; + type Options = (); + type Context = (); + type Output = impl CompileShader + + ReflectShader; + + fn from_compilation( + compile: SpirvCompilation, + ) -> Result, ShaderReflectError> { + Ok(CompilerBackend { + backend: NagaReflect::try_from(&compile)?, + }) + } +} diff --git a/librashader-reflect/src/back/spirv.rs b/librashader-reflect/src/back/spirv.rs index ef86de1..9881bf1 100644 --- a/librashader-reflect/src/back/spirv.rs +++ b/librashader-reflect/src/back/spirv.rs @@ -2,9 +2,12 @@ use crate::back::targets::SPIRV; use crate::back::{CompileShader, CompilerBackend, FromCompilation, ShaderCompilerOutput}; use crate::error::{ShaderCompileError, ShaderReflectError}; use crate::front::SpirvCompilation; -use crate::reflect::cross::{GlslReflect, SpirvCross}; +use crate::reflect::cross::glsl::GlslReflect; +use crate::reflect::cross::SpirvCross; +use crate::reflect::naga::{Naga, NagaLoweringOptions, NagaReflect}; use crate::reflect::semantics::ShaderSemantics; use crate::reflect::{ReflectShader, ShaderReflection}; +use naga::Module; pub(crate) struct WriteSpirV { // rely on GLSL to provide out reflection but we don't actually need the AST. @@ -61,3 +64,30 @@ impl CompileShader for WriteSpirV { }) } } + +/// The context for a SPIRV compilation via Naga +pub struct NagaSpirvContext { + pub fragment: Module, + pub vertex: Module, +} + +impl FromCompilation for SPIRV { + type Target = SPIRV; + type Options = NagaSpirvOptions; + type Context = NagaSpirvContext; + type Output = impl CompileShader + + ReflectShader; + + fn from_compilation( + compile: SpirvCompilation, + ) -> Result, ShaderReflectError> { + Ok(CompilerBackend { + backend: NagaReflect::try_from(&compile)?, + }) + } +} + +pub struct NagaSpirvOptions { + pub lowering: NagaLoweringOptions, + pub version: (u8, u8), +} diff --git a/librashader-reflect/src/back/wgsl.rs b/librashader-reflect/src/back/wgsl.rs index bb401ac..c9ebce5 100644 --- a/librashader-reflect/src/back/wgsl.rs +++ b/librashader-reflect/src/back/wgsl.rs @@ -1,12 +1,10 @@ use crate::back::targets::WGSL; -use crate::back::{CompileShader, CompilerBackend, FromCompilation, ShaderCompilerOutput}; -use crate::error::{ShaderCompileError, ShaderReflectError}; +use crate::back::{CompileShader, CompilerBackend, FromCompilation}; +use crate::error::ShaderReflectError; use crate::front::SpirvCompilation; -use crate::reflect::naga::{Naga, NagaReflect}; +use crate::reflect::naga::{Naga, NagaLoweringOptions, NagaReflect}; use crate::reflect::ReflectShader; -use naga::back::wgsl::WriterFlags; -use naga::valid::{Capabilities, ValidationFlags}; -use naga::{AddressSpace, Module}; +use naga::Module; /// The context for a WGSL compilation via Naga pub struct NagaWgslContext { @@ -14,16 +12,9 @@ pub struct NagaWgslContext { pub vertex: Module, } -/// Compiler options for WGSL -#[derive(Debug, Default, Clone)] -pub struct WgslCompileOptions { - pub write_pcb_as_ubo: bool, - pub sampler_bind_group: u32, -} - impl FromCompilation for WGSL { type Target = WGSL; - type Options = WgslCompileOptions; + type Options = NagaLoweringOptions; type Context = NagaWgslContext; type Output = impl CompileShader + ReflectShader; @@ -32,98 +23,7 @@ impl FromCompilation for WGSL { compile: SpirvCompilation, ) -> Result, ShaderReflectError> { Ok(CompilerBackend { - backend: NagaReflect::create_reflection(&compile)?, - }) - } -} - -impl CompileShader for NagaReflect { - type Options = WgslCompileOptions; - type Context = NagaWgslContext; - - fn compile( - mut self, - options: Self::Options, - ) -> Result, ShaderCompileError> { - fn write_wgsl(module: &Module) -> Result { - let mut valid = - naga::valid::Validator::new(ValidationFlags::all(), Capabilities::empty()); - let info = valid.validate(&module)?; - - let wgsl = naga::back::wgsl::write_string(&module, &info, WriterFlags::EXPLICIT_TYPES)?; - Ok(wgsl) - } - - if options.write_pcb_as_ubo { - for (_, gv) in self.fragment.global_variables.iter_mut() { - if gv.space == AddressSpace::PushConstant { - gv.space = AddressSpace::Uniform; - } - } - - for (_, gv) in self.vertex.global_variables.iter_mut() { - if gv.space == AddressSpace::PushConstant { - gv.space = AddressSpace::Uniform; - } - } - } else { - for (_, gv) in self.fragment.global_variables.iter_mut() { - if gv.space == AddressSpace::PushConstant { - gv.binding = None; - } - } - } - - // Reassign shit. - let images = self - .fragment - .global_variables - .iter() - .filter(|&(_, gv)| { - let ty = &self.fragment.types[gv.ty]; - match ty.inner { - naga::TypeInner::Image { .. } => true, - naga::TypeInner::BindingArray { base, .. } => { - let ty = &self.fragment.types[base]; - matches!(ty.inner, naga::TypeInner::Image { .. }) - } - _ => false, - } - }) - .map(|(_, gv)| (gv.binding.clone(), gv.space)) - .collect::>(); - - self.fragment - .global_variables - .iter_mut() - .filter(|(_, gv)| { - let ty = &self.fragment.types[gv.ty]; - match ty.inner { - naga::TypeInner::Sampler { .. } => true, - naga::TypeInner::BindingArray { base, .. } => { - let ty = &self.fragment.types[base]; - matches!(ty.inner, naga::TypeInner::Sampler { .. }) - } - _ => false, - } - }) - .for_each(|(_, gv)| { - if images.contains(&(gv.binding.clone(), gv.space)) { - if let Some(binding) = &mut gv.binding { - binding.group = options.sampler_bind_group; - } - } - }); - - let fragment = write_wgsl(&self.fragment)?; - let vertex = write_wgsl(&self.vertex)?; - Ok(ShaderCompilerOutput { - vertex, - fragment, - context: NagaWgslContext { - fragment: self.fragment, - vertex: self.vertex, - }, + backend: NagaReflect::try_from(&compile)?, }) } } @@ -131,12 +31,13 @@ impl CompileShader for NagaReflect { #[cfg(test)] mod test { use crate::back::targets::WGSL; - use crate::back::wgsl::WgslCompileOptions; use crate::back::{CompileShader, FromCompilation}; + use crate::reflect::naga::NagaLoweringOptions; use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics}; use crate::reflect::ReflectShader; use librashader_preprocess::ShaderSource; use rustc_hash::FxHashMap; + use bitflags::Flags; #[test] pub fn test_into() { @@ -170,7 +71,7 @@ mod test { .expect(""); let compiled = wgsl - .compile(WgslCompileOptions { + .compile(NagaLoweringOptions { write_pcb_as_ubo: true, sampler_bind_group: 1, }) diff --git a/librashader-reflect/src/error.rs b/librashader-reflect/src/error.rs index bb79cd0..1ecd30a 100644 --- a/librashader-reflect/src/error.rs +++ b/librashader-reflect/src/error.rs @@ -28,9 +28,15 @@ pub enum ShaderCompileError { SpirvToDxilCompileError(#[from] spirv_to_dxil::SpirvToDxilError), /// Error when transpiling from naga - #[cfg(feature = "wgsl")] + #[cfg(all(feature = "wgsl", feature = "naga"))] #[error("naga-wgsl")] NagaWgslError(#[from] naga::back::wgsl::Error), + + /// Error when transpiling from naga + #[cfg(feature = "naga")] + #[error("naga-spv")] + NagaGlslError(#[from] naga::back::spv::Error), + /// Error when transpiling from naga #[cfg(feature = "wgsl")] #[error("naga-wgsl")] diff --git a/librashader-reflect/src/reflect/cross/glsl.rs b/librashader-reflect/src/reflect/cross/glsl.rs new file mode 100644 index 0000000..68b1c41 --- /dev/null +++ b/librashader-reflect/src/reflect/cross/glsl.rs @@ -0,0 +1,142 @@ +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; + +pub(crate) type GlslReflect = CrossReflect; + +impl CompileShader for CrossReflect { + type Options = spirv_cross::glsl::Version; + type Context = CrossGlslContext; + + fn compile( + mut self, + version: Self::Options, + ) -> Result, ShaderCompileError> { + let mut options: spirv_cross::glsl::CompilerOptions = Default::default(); + 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)?; + + let vertex_resources = self.vertex.get_shader_resources()?; + let fragment_resources = self.fragment.get_shader_resources()?; + + for res in &vertex_resources.stage_inputs { + self.vertex.unset_decoration(res.id, Decoration::Location)?; + } + for res in &vertex_resources.stage_outputs { + // 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)?; + } + for res in &fragment_resources.stage_inputs { + // 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)?; + } + + if vertex_resources.push_constant_buffers.len() > 1 { + return Err(ShaderCompileError::SpirvCrossCompileError( + ErrorCode::CompilationError(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")?; + self.vertex + .set_name(res.base_type_id, "LIBRA_PUSH_VERTEX")?; + } + + // todo: options + let _flatten = false; + + if vertex_resources.uniform_buffers.len() > 1 { + return Err(ShaderCompileError::SpirvCrossCompileError( + ErrorCode::CompilationError(String::from( + "Cannot have more than one uniform buffer", + )), + )); + } + for res in &vertex_resources.uniform_buffers { + // 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 + .unset_decoration(res.id, Decoration::DescriptorSet)?; + self.vertex.unset_decoration(res.id, Decoration::Binding)?; + } + + if fragment_resources.push_constant_buffers.len() > 1 { + return Err(ShaderCompileError::SpirvCrossCompileError( + ErrorCode::CompilationError(String::from( + "Cannot have more than one push constant buffer", + )), + )); + } + for res in &fragment_resources.push_constant_buffers { + self.fragment + .set_name(res.id, "LIBRA_PUSH_FRAGMENT_INSTANCE")?; + self.fragment + .set_name(res.base_type_id, "LIBRA_PUSH_FRAGMENT")?; + } + + if fragment_resources.uniform_buffers.len() > 1 { + return Err(ShaderCompileError::SpirvCrossCompileError( + ErrorCode::CompilationError(String::from( + "Cannot have more than one uniform buffer", + )), + )); + } + + for res in &fragment_resources.uniform_buffers { + // if flatten { + // self.fragment.flatten_buffer_block(res.id)?; + // } + self.fragment + .set_name(res.id, "LIBRA_UBO_FRAGMENT_INSTANCE")?; + self.fragment + .set_name(res.base_type_id, "LIBRA_UBO_FRAGMENT")?; + self.fragment + .unset_decoration(res.id, Decoration::DescriptorSet)?; + self.fragment + .unset_decoration(res.id, Decoration::Binding)?; + } + + let mut texture_fixups = Vec::new(); + for res in fragment_resources.sampled_images { + let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?; + self.fragment + .unset_decoration(res.id, Decoration::DescriptorSet)?; + self.fragment + .unset_decoration(res.id, Decoration::Binding)?; + let mut name = res.name; + name.push('\0'); + texture_fixups.push((name, binding)); + } + + Ok(ShaderCompilerOutput { + vertex: self.vertex.compile()?, + fragment: self.fragment.compile()?, + context: CrossGlslContext { + sampler_bindings: texture_fixups, + artifact: CompiledProgram { + vertex: CompiledAst(self.vertex), + fragment: CompiledAst(self.fragment), + }, + }, + }) + } +} diff --git a/librashader-reflect/src/reflect/cross/hlsl.rs b/librashader-reflect/src/reflect/cross/hlsl.rs new file mode 100644 index 0000000..4788c0f --- /dev/null +++ b/librashader-reflect/src/reflect/cross/hlsl.rs @@ -0,0 +1,36 @@ +use crate::back::hlsl::CrossHlslContext; +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; + +pub(crate) type HlslReflect = CrossReflect; + +impl CompileShader for CrossReflect { + type Options = Option; + type Context = CrossHlslContext; + + fn compile( + 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; + + self.vertex.set_compiler_options(&options)?; + self.fragment.set_compiler_options(&options)?; + + Ok(ShaderCompilerOutput { + vertex: self.vertex.compile()?, + fragment: self.fragment.compile()?, + context: CrossHlslContext { + artifact: CompiledProgram { + vertex: CompiledAst(self.vertex), + fragment: CompiledAst(self.fragment), + }, + }, + }) + } +} diff --git a/librashader-reflect/src/reflect/cross.rs b/librashader-reflect/src/reflect/cross/mod.rs similarity index 80% rename from librashader-reflect/src/reflect/cross.rs rename to librashader-reflect/src/reflect/cross/mod.rs index 85637de..c07a810 100644 --- a/librashader-reflect/src/reflect/cross.rs +++ b/librashader-reflect/src/reflect/cross/mod.rs @@ -1,4 +1,8 @@ -use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError}; +pub mod glsl; +pub mod hlsl; +pub mod msl; + +use crate::error::{SemanticsErrorKind, ShaderReflectError}; use crate::front::SpirvCompilation; use crate::reflect::semantics::{ BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderReflection, ShaderSemantics, @@ -10,19 +14,13 @@ use crate::reflect::{align_uniform_size, ReflectShader}; use std::ops::Deref; use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type}; -use spirv_cross::{glsl, hlsl, ErrorCode}; +use spirv_cross::ErrorCode; -use crate::back::cross::{CrossGlslContext, CrossHlslContext, HlslShaderModel}; -use crate::back::targets::{GLSL, HLSL}; -use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData}; /// Reflect shaders under SPIRV-Cross semantics. pub struct SpirvCross; -pub(crate) type HlslReflect = CrossReflect; -pub(crate) type GlslReflect = CrossReflect; - // This is "probably" OK. unsafe impl Send for CrossReflect where @@ -732,175 +730,13 @@ where } } -impl CompileShader for CrossReflect { - type Options = glsl::Version; - type Context = CrossGlslContext; - - fn compile( - mut self, - version: Self::Options, - ) -> Result, ShaderCompileError> { - let mut options: glsl::CompilerOptions = Default::default(); - options.version = version; - options.fragment.default_float_precision = glsl::Precision::High; - options.fragment.default_int_precision = glsl::Precision::High; - options.enable_420_pack_extension = false; - - self.vertex.set_compiler_options(&options)?; - self.fragment.set_compiler_options(&options)?; - - let vertex_resources = self.vertex.get_shader_resources()?; - let fragment_resources = self.fragment.get_shader_resources()?; - - for res in &vertex_resources.stage_inputs { - self.vertex.unset_decoration(res.id, Decoration::Location)?; - } - for res in &vertex_resources.stage_outputs { - // 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)?; - } - for res in &fragment_resources.stage_inputs { - // 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)?; - } - - if vertex_resources.push_constant_buffers.len() > 1 { - return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(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")?; - self.vertex - .set_name(res.base_type_id, "LIBRA_PUSH_VERTEX")?; - } - - // todo: options - let _flatten = false; - - if vertex_resources.uniform_buffers.len() > 1 { - return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( - "Cannot have more than one uniform buffer", - )), - )); - } - for res in &vertex_resources.uniform_buffers { - // 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 - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.vertex.unset_decoration(res.id, Decoration::Binding)?; - } - - if fragment_resources.push_constant_buffers.len() > 1 { - return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( - "Cannot have more than one push constant buffer", - )), - )); - } - for res in &fragment_resources.push_constant_buffers { - self.fragment - .set_name(res.id, "LIBRA_PUSH_FRAGMENT_INSTANCE")?; - self.fragment - .set_name(res.base_type_id, "LIBRA_PUSH_FRAGMENT")?; - } - - if fragment_resources.uniform_buffers.len() > 1 { - return Err(ShaderCompileError::SpirvCrossCompileError( - ErrorCode::CompilationError(String::from( - "Cannot have more than one uniform buffer", - )), - )); - } - - for res in &fragment_resources.uniform_buffers { - // if flatten { - // self.fragment.flatten_buffer_block(res.id)?; - // } - self.fragment - .set_name(res.id, "LIBRA_UBO_FRAGMENT_INSTANCE")?; - self.fragment - .set_name(res.base_type_id, "LIBRA_UBO_FRAGMENT")?; - self.fragment - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.fragment - .unset_decoration(res.id, Decoration::Binding)?; - } - - let mut texture_fixups = Vec::new(); - for res in fragment_resources.sampled_images { - let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?; - self.fragment - .unset_decoration(res.id, Decoration::DescriptorSet)?; - self.fragment - .unset_decoration(res.id, Decoration::Binding)?; - let mut name = res.name; - name.push('\0'); - texture_fixups.push((name, binding)); - } - - Ok(ShaderCompilerOutput { - vertex: self.vertex.compile()?, - fragment: self.fragment.compile()?, - context: CrossGlslContext { - sampler_bindings: texture_fixups, - artifact: CompiledProgram { - vertex: CompiledAst(self.vertex), - fragment: CompiledAst(self.fragment), - }, - }, - }) - } -} - -impl CompileShader for CrossReflect { - type Options = Option; - type Context = CrossHlslContext; - - fn compile( - mut self, - options: Self::Options, - ) -> Result, ShaderCompileError> { - let sm = options.unwrap_or(HlslShaderModel::V5_0); - let mut options = hlsl::CompilerOptions::default(); - options.shader_model = sm; - - self.vertex.set_compiler_options(&options)?; - self.fragment.set_compiler_options(&options)?; - - Ok(ShaderCompilerOutput { - vertex: self.vertex.compile()?, - fragment: self.fragment.compile()?, - context: CrossHlslContext { - artifact: CompiledProgram { - vertex: CompiledAst(self.vertex), - fragment: CompiledAst(self.fragment), - }, - }, - }) - } -} - #[cfg(test)] mod test { use crate::reflect::cross::CrossReflect; use crate::reflect::ReflectShader; use rustc_hash::FxHashMap; - use crate::back::CompileShader; - use crate::front::{Glslang, ShaderInputCompiler, SpirvCompilation}; + use crate::front::{Glslang, ShaderInputCompiler}; use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics}; use librashader_preprocess::ShaderSource; use spirv_cross::glsl; diff --git a/librashader-reflect/src/reflect/cross/msl.rs b/librashader-reflect/src/reflect/cross/msl.rs new file mode 100644 index 0000000..dd80654 --- /dev/null +++ b/librashader-reflect/src/reflect/cross/msl.rs @@ -0,0 +1,39 @@ +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; + +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 options = spirv_cross::msl::CompilerOptions::default(); + options.version = version; + + // This is actually all sorts of broken because there's no way to change bindings + // with the current version of spirv_cross. + + self.vertex.set_compiler_options(&options)?; + self.fragment.set_compiler_options(&options)?; + + Ok(ShaderCompilerOutput { + vertex: self.vertex.compile()?, + fragment: self.fragment.compile()?, + context: CrossMslContext { + artifact: CompiledProgram { + vertex: CompiledAst(self.vertex), + fragment: CompiledAst(self.fragment), + }, + }, + }) + } +} diff --git a/librashader-reflect/src/reflect/naga/mod.rs b/librashader-reflect/src/reflect/naga/mod.rs index 928837d..78f897a 100644 --- a/librashader-reflect/src/reflect/naga/mod.rs +++ b/librashader-reflect/src/reflect/naga/mod.rs @@ -1,8 +1,10 @@ mod lower_samplers; +pub mod msl; +pub mod spirv; +pub mod wgsl; use crate::error::{SemanticsErrorKind, ShaderReflectError}; -use crate::error; use crate::front::SpirvCompilation; use naga::{ AddressSpace, Binding, GlobalVariable, Handle, ImageClass, Module, ResourceBinding, Scalar, @@ -32,10 +34,82 @@ pub(crate) struct NagaReflect { pub(crate) fragment: Module, } +/// Options to lower samplers and pcbs +#[derive(Debug, Default, Clone)] +pub struct NagaLoweringOptions { + pub write_pcb_as_ubo: bool, + pub sampler_bind_group: u32, +} + impl NagaReflect { - pub(crate) fn create_reflection( - compile: &SpirvCompilation, - ) -> Result { + pub fn do_lowering(&mut self, options: &NagaLoweringOptions) { + if options.write_pcb_as_ubo { + for (_, gv) in self.fragment.global_variables.iter_mut() { + if gv.space == AddressSpace::PushConstant { + gv.space = AddressSpace::Uniform; + } + } + + for (_, gv) in self.vertex.global_variables.iter_mut() { + if gv.space == AddressSpace::PushConstant { + gv.space = AddressSpace::Uniform; + } + } + } else { + for (_, gv) in self.fragment.global_variables.iter_mut() { + if gv.space == AddressSpace::PushConstant { + gv.binding = None; + } + } + } + + // Reassign shit. + let images = self + .fragment + .global_variables + .iter() + .filter(|&(_, gv)| { + let ty = &self.fragment.types[gv.ty]; + match ty.inner { + naga::TypeInner::Image { .. } => true, + naga::TypeInner::BindingArray { base, .. } => { + let ty = &self.fragment.types[base]; + matches!(ty.inner, naga::TypeInner::Image { .. }) + } + _ => false, + } + }) + .map(|(_, gv)| (gv.binding.clone(), gv.space)) + .collect::>(); + + self.fragment + .global_variables + .iter_mut() + .filter(|(_, gv)| { + let ty = &self.fragment.types[gv.ty]; + match ty.inner { + naga::TypeInner::Sampler { .. } => true, + naga::TypeInner::BindingArray { base, .. } => { + let ty = &self.fragment.types[base]; + matches!(ty.inner, naga::TypeInner::Sampler { .. }) + } + _ => false, + } + }) + .for_each(|(_, gv)| { + if images.contains(&(gv.binding.clone(), gv.space)) { + if let Some(binding) = &mut gv.binding { + binding.group = options.sampler_bind_group; + } + } + }); + } +} + +impl TryFrom<&SpirvCompilation> for NagaReflect { + type Error = ShaderReflectError; + + fn try_from(compile: &SpirvCompilation) -> Result { fn lower_fragment_shader(words: &[u32]) -> Vec { let mut loader = rspirv::dr::Loader::new(); rspirv::binary::parse_words(words, &mut loader).unwrap(); @@ -67,6 +141,7 @@ impl NagaReflect { Ok(NagaReflect { vertex, fragment }) } } + impl ValidateTypeSemantics<&TypeInner> for UniqueSemantics { fn validate_type(&self, ty: &&TypeInner) -> Option { let (TypeInner::Vector { .. } | TypeInner::Scalar { .. } | TypeInner::Matrix { .. }) = *ty diff --git a/librashader-reflect/src/reflect/naga/msl.rs b/librashader-reflect/src/reflect/naga/msl.rs new file mode 100644 index 0000000..6b48c0c --- /dev/null +++ b/librashader-reflect/src/reflect/naga/msl.rs @@ -0,0 +1,16 @@ +use crate::back::targets::MSL; +use crate::back::{CompileShader, ShaderCompilerOutput}; +use crate::error::ShaderCompileError; +use crate::reflect::naga::NagaReflect; + +impl CompileShader for NagaReflect { + type Options = (); + type Context = (); + + fn compile( + self, + options: Self::Options, + ) -> Result, ShaderCompileError> { + todo!() + } +} diff --git a/librashader-reflect/src/reflect/naga/spirv.rs b/librashader-reflect/src/reflect/naga/spirv.rs new file mode 100644 index 0000000..7d95041 --- /dev/null +++ b/librashader-reflect/src/reflect/naga/spirv.rs @@ -0,0 +1,54 @@ +use crate::back::spirv::{NagaSpirvContext, NagaSpirvOptions}; +use crate::back::targets::SPIRV; +use crate::back::{CompileShader, ShaderCompilerOutput}; +use crate::error::ShaderCompileError; +use crate::reflect::naga::NagaReflect; +use naga::back::spv::PipelineOptions; +use naga::valid::{Capabilities, ValidationFlags}; +use naga::Module; + +impl CompileShader for NagaReflect { + type Options = NagaSpirvOptions; + type Context = NagaSpirvContext; + + fn compile( + mut self, + options: Self::Options, + ) -> Result, Self::Context>, ShaderCompileError> { + fn write_spv( + module: &Module, + stage: naga::ShaderStage, + version: (u8, u8), + ) -> Result, ShaderCompileError> { + let mut valid = + naga::valid::Validator::new(ValidationFlags::all(), Capabilities::empty()); + let info = valid.validate(&module)?; + let mut options = naga::back::spv::Options::default(); + options.lang_version = version; + + let spv = naga::back::spv::write_vec( + &module, + &info, + &options, + Some(&PipelineOptions { + shader_stage: stage, + entry_point: "main".to_string(), + }), + )?; + Ok(spv) + } + + self.do_lowering(&options.lowering); + + let fragment = write_spv(&self.fragment, naga::ShaderStage::Fragment, options.version)?; + let vertex = write_spv(&self.vertex, naga::ShaderStage::Vertex, options.version)?; + Ok(ShaderCompilerOutput { + vertex, + fragment, + context: NagaSpirvContext { + fragment: self.fragment, + vertex: self.vertex, + }, + }) + } +} diff --git a/librashader-reflect/src/reflect/naga/wgsl.rs b/librashader-reflect/src/reflect/naga/wgsl.rs new file mode 100644 index 0000000..98ee8c6 --- /dev/null +++ b/librashader-reflect/src/reflect/naga/wgsl.rs @@ -0,0 +1,40 @@ +use crate::back::targets::WGSL; +use crate::back::wgsl::NagaWgslContext; +use crate::back::{CompileShader, ShaderCompilerOutput}; +use crate::error::ShaderCompileError; +use crate::reflect::naga::{NagaLoweringOptions, NagaReflect}; +use naga::back::wgsl::WriterFlags; +use naga::valid::{Capabilities, ValidationFlags}; +use naga::Module; + +impl CompileShader for NagaReflect { + type Options = NagaLoweringOptions; + type Context = NagaWgslContext; + + fn compile( + mut self, + options: Self::Options, + ) -> Result, ShaderCompileError> { + fn write_wgsl(module: &Module) -> Result { + let mut valid = + naga::valid::Validator::new(ValidationFlags::all(), Capabilities::empty()); + let info = valid.validate(&module)?; + + let wgsl = naga::back::wgsl::write_string(&module, &info, WriterFlags::EXPLICIT_TYPES)?; + Ok(wgsl) + } + + self.do_lowering(&options); + + let fragment = write_wgsl(&self.fragment)?; + let vertex = write_wgsl(&self.vertex)?; + Ok(ShaderCompilerOutput { + vertex, + fragment, + context: NagaWgslContext { + fragment: self.fragment, + vertex: self.vertex, + }, + }) + } +} diff --git a/librashader-runtime-d3d12/src/graphics_pipeline.rs b/librashader-runtime-d3d12/src/graphics_pipeline.rs index 41267ed..743ae93 100644 --- a/librashader-runtime-d3d12/src/graphics_pipeline.rs +++ b/librashader-runtime-d3d12/src/graphics_pipeline.rs @@ -3,7 +3,7 @@ use crate::error::assume_d3d12_init; use crate::error::FilterChainError::Direct3DOperationError; use crate::{error, util}; use librashader_cache::{cache_pipeline, cache_shader_object}; -use librashader_reflect::back::cross::CrossHlslContext; +use librashader_reflect::back::hlsl::CrossHlslContext; use librashader_reflect::back::dxil::DxilObject; use librashader_reflect::back::ShaderCompilerOutput; use std::mem::ManuallyDrop; diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/filter_impl.rs index 72a1c42..c382d86 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/filter_impl.rs @@ -13,7 +13,7 @@ use gl::types::GLuint; use librashader_common::Viewport; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; -use librashader_reflect::back::cross::GlslVersion; +use librashader_reflect::back::glsl::GlslVersion; use librashader_reflect::back::targets::GLSL; use librashader_reflect::back::{CompileReflectShader, CompileShader}; use librashader_reflect::front::{Glslang, SpirvCompilation}; diff --git a/librashader-runtime-gl/src/gl/gl3/compile_program.rs b/librashader-runtime-gl/src/gl/gl3/compile_program.rs index 92410d1..9477599 100644 --- a/librashader-runtime-gl/src/gl/gl3/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl3/compile_program.rs @@ -3,7 +3,7 @@ use crate::error::FilterChainError; use crate::gl::CompileProgram; use crate::util; use gl::types::{GLint, GLuint}; -use librashader_reflect::back::cross::CrossGlslContext; +use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use spirv_cross::spirv::Decoration; diff --git a/librashader-runtime-gl/src/gl/gl46/compile_program.rs b/librashader-runtime-gl/src/gl/gl46/compile_program.rs index 971c39c..5595dd7 100644 --- a/librashader-runtime-gl/src/gl/gl46/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl46/compile_program.rs @@ -4,7 +4,7 @@ use crate::gl::CompileProgram; use crate::util; use gl::types::{GLint, GLsizei, GLuint}; use librashader_cache::Cacheable; -use librashader_reflect::back::cross::CrossGlslContext; +use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use spirv_cross::spirv::Decoration; diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index 6d17a79..d73854e 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -11,7 +11,7 @@ pub use framebuffer::GLFramebuffer; use gl::types::{GLenum, GLuint}; use librashader_common::{ImageFormat, Size}; use librashader_presets::{Scale2D, TextureConfig}; -use librashader_reflect::back::cross::CrossGlslContext; +use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::semantics::{BufferReflection, TextureBinding}; use librashader_runtime::uniforms::UniformStorageAccess; diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index d1d50cd..5179118 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -2,7 +2,7 @@ use gl::types::{GLenum, GLuint}; use crate::error; use crate::error::FilterChainError; -use librashader_reflect::back::cross::GlslVersion; +use librashader_reflect::back::glsl::GlslVersion; pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> error::Result { let (shader, compile_status) = unsafe { diff --git a/librashader-runtime-wgpu/src/filter_chain.rs b/librashader-runtime-wgpu/src/filter_chain.rs index a7f7cc0..90a2d6a 100644 --- a/librashader-runtime-wgpu/src/filter_chain.rs +++ b/librashader-runtime-wgpu/src/filter_chain.rs @@ -21,7 +21,7 @@ use crate::buffer::WgpuStagedBuffer; use crate::draw_quad::DrawQuad; use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode}; use librashader_reflect::back::wgsl::WgslCompileOptions; -use librashader_reflect::reflect::naga::Naga; +use librashader_reflect::reflect::naga::{Naga, NagaLoweringOptions}; use librashader_runtime::framebuffer::FramebufferInit; use librashader_runtime::render_target::RenderTarget; use librashader_runtime::scaling::ScaleFramebuffer; @@ -270,7 +270,7 @@ impl FilterChainWgpu { .enumerate() .map(|(index, (config, source, mut reflect))| { let reflection = reflect.reflect(index, semantics)?; - let wgsl = reflect.compile(WgslCompileOptions { + let wgsl = reflect.compile(NagaLoweringOptions { write_pcb_as_ubo: true, sampler_bind_group: 1, })?; diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 320631b..934a27b 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -158,15 +158,15 @@ pub mod reflect { pub mod cross { /// The version of GLSL to target. /// - pub use librashader_reflect::back::cross::GlslVersion; + pub use librashader_reflect::back::glsl::GlslVersion; /// The HLSL Shader Model to target. /// - pub use librashader_reflect::back::cross::HlslShaderModel; + pub use librashader_reflect::back::glsl::HlslShaderModel; - pub use librashader_reflect::back::cross::CrossGlslContext; + pub use librashader_reflect::back::glsl::CrossGlslContext; - pub use librashader_reflect::back::cross::CrossHlslContext; + pub use librashader_reflect::back::hlsl::CrossHlslContext; pub use librashader_reflect::reflect::cross::CompiledAst;