diff --git a/librashader-reflect/Cargo.toml b/librashader-reflect/Cargo.toml index 5966369..caa365b 100644 --- a/librashader-reflect/Cargo.toml +++ b/librashader-reflect/Cargo.toml @@ -23,11 +23,13 @@ librashader-common = { path = "../librashader-common", version = "0.1.0-beta.10" librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-beta.10" } librashader-presets = { path = "../librashader-presets", version = "0.1.0-beta.10" } +spirv-to-dxil = { version = "0.2", optional = true } naga = { version = "0.10.0", features = ["glsl-in", "spv-in", "spv-out", "glsl-out", "wgsl-out"], optional = true } [features] -default = [] +default = ["dxil"] unstable-naga = [ "naga" ] standalone = ["shaderc/build-from-source"] +dxil = ["spirv-to-dxil"] [dev-dependencies] diff --git a/librashader-reflect/src/back/dxil.rs b/librashader-reflect/src/back/dxil.rs new file mode 100644 index 0000000..ff108f1 --- /dev/null +++ b/librashader-reflect/src/back/dxil.rs @@ -0,0 +1,77 @@ +pub use spirv_to_dxil::DxilObject; +pub use spirv_to_dxil::ShaderModel; +use spirv_to_dxil::{ShaderStage, ValidatorVersion}; +use crate::back::{CompilerBackend, CompileShader, FromCompilation, ShaderCompilerOutput}; +use crate::back::spirv::WriteSpirV; + +use crate::back::targets::{DXIL, OutputTarget}; +use crate::error::{ShaderCompileError, ShaderReflectError}; +use crate::front::GlslangCompilation; +use crate::reflect::cross::GlslReflect; +use crate::reflect::ReflectShader; + +impl OutputTarget for DXIL { + type Output = DxilObject; +} + +impl FromCompilation for DXIL { + type Target = DXIL; + type Options = Option; + type Context = (); + type Output = impl CompileShader + + ReflectShader; + + fn from_compilation( + compile: GlslangCompilation, + ) -> Result, ShaderReflectError> { + let vertex = compile.vertex.as_binary().to_vec(); + let fragment = compile.fragment.as_binary().to_vec(); + let reflect = GlslReflect::try_from(compile)?; + Ok(CompilerBackend { + // we can just reuse WriteSpirV as the backend. + backend: WriteSpirV { + reflect, + vertex, + fragment, + }, + }) + } +} + +impl CompileShader for WriteSpirV { + type Options = Option; + type Context = (); + + fn compile( + self, + options: Self::Options, + ) -> Result, ShaderCompileError> { + let sm = options.unwrap_or(ShaderModel::ShaderModel6_0); + + // todo: do we want to allow other entry point names? + let vertex = + spirv_to_dxil::spirv_to_dxil(&self.vertex, + None, "main", + ShaderStage::Vertex, + sm, + ValidatorVersion::None, + Default::default()) + .map_err(|s| ShaderCompileError::SpirvToDxilCompileError(s))?; + + + let fragment = + spirv_to_dxil::spirv_to_dxil(&self.fragment, + None, "main", + ShaderStage::Fragment, + ShaderModel::ShaderModel6_0, + ValidatorVersion::None, + Default::default()) + .map_err(|s| ShaderCompileError::SpirvToDxilCompileError(s))?; + + Ok(ShaderCompilerOutput { + vertex, + fragment, + context: (), + }) + } +} diff --git a/librashader-reflect/src/back/mod.rs b/librashader-reflect/src/back/mod.rs index 3c2ca64..f82d660 100644 --- a/librashader-reflect/src/back/mod.rs +++ b/librashader-reflect/src/back/mod.rs @@ -1,6 +1,7 @@ pub mod cross; mod spirv; pub mod targets; +pub mod dxil; use crate::back::targets::OutputTarget; use crate::error::{ShaderCompileError, ShaderReflectError}; diff --git a/librashader-reflect/src/back/spirv.rs b/librashader-reflect/src/back/spirv.rs index 3aa583d..9f02f1a 100644 --- a/librashader-reflect/src/back/spirv.rs +++ b/librashader-reflect/src/back/spirv.rs @@ -6,11 +6,11 @@ use crate::reflect::cross::GlslReflect; use crate::reflect::semantics::ShaderSemantics; use crate::reflect::{ReflectShader, ShaderReflection}; -struct WriteSpirV { +pub(crate) struct WriteSpirV { // rely on GLSL to provide out reflection but we don't actually need the AST. - reflect: GlslReflect, - vertex: Vec, - fragment: Vec, + pub(crate) reflect: GlslReflect, + pub(crate) vertex: Vec, + pub(crate) fragment: Vec, } impl FromCompilation for SPIRV { diff --git a/librashader-reflect/src/back/targets.rs b/librashader-reflect/src/back/targets.rs index 6c69ec4..abc5fc1 100644 --- a/librashader-reflect/src/back/targets.rs +++ b/librashader-reflect/src/back/targets.rs @@ -10,8 +10,13 @@ pub struct GLSL; pub struct HLSL; /// Shader compiler target for SPIR-V. pub struct SPIRV; -/// Shader compiler target for MSL +/// Shader compiler target for MSL. pub struct MSL; +/// Shader compiler target for DXIL. +/// +/// The resulting DXIL object is always unvalidated and +/// must be validated using platform APIs before usage. +pub struct DXIL; impl OutputTarget for GLSL { type Output = String; diff --git a/librashader-reflect/src/error.rs b/librashader-reflect/src/error.rs index 0abb47d..6bda1b3 100644 --- a/librashader-reflect/src/error.rs +++ b/librashader-reflect/src/error.rs @@ -21,6 +21,11 @@ pub enum ShaderCompileError { /// Error when transpiling from spirv-cross. #[error("cross")] SpirvCrossCompileError(#[from] spirv_cross::ErrorCode), + + /// Error when transpiling from spirv-to-dxil + #[cfg(feature = "dxil")] + #[error("spirv-to-dxil")] + SpirvToDxilCompileError(String), } /// The error kind encountered when reflecting shader semantics. diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 490ef6c..85aca86 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -153,6 +153,16 @@ pub mod reflect { pub use librashader_reflect::reflect::cross::CompiledProgram; } + + /// DXIL reflection via spirv-to-dxil. + pub mod dxil { + /// The maximum shader model to use when compiling the DXIL blob. + pub use librashader_reflect::back::dxil::ShaderModel; + + /// A compiled DXIL artifact. + pub use librashader_reflect::back::dxil::DxilObject; + } + pub use librashader_reflect::reflect::semantics::BindingMeta; pub use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};