reflect: move folder structure around to be a little better

This commit is contained in:
chyyran 2024-02-11 02:23:01 -05:00 committed by Ronny Chan
parent e1f62fc984
commit c67e9f4801
25 changed files with 570 additions and 331 deletions

View file

@ -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" ]
msl = [ "spirv_cross/msl", "naga/msl-out" ]

View file

@ -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 {

View file

@ -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<SpirvCompilation, SpirvCross> for GLSL {
})
}
}
/// The context for a HLSL compilation via spirv-cross.
pub struct CrossHlslContext {
/// The compiled HLSL program.
pub artifact: CompiledProgram<spirv_cross::hlsl::Target>,
}
impl FromCompilation<SpirvCompilation, SpirvCross> for HLSL {
type Target = HLSL;
type Options = Option<HlslShaderModel>;
type Context = CrossHlslContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
fn from_compilation(
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: HlslReflect::try_from(&compile)?,
})
}
}

View file

@ -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<spirv_cross::hlsl::Target>,
}
impl FromCompilation<SpirvCompilation, SpirvCross> for HLSL {
type Target = HLSL;
type Options = Option<HlslShaderModel>;
type Context = CrossHlslContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
fn from_compilation(
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: HlslReflect::try_from(&compile)?,
})
}
}

View file

@ -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;

View file

@ -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<spirv_cross::msl::Target>,
}
impl FromCompilation<SpirvCompilation, SpirvCross> for MSL {
type Target = MSL;
type Options = Option<spirv_cross::msl::Version>;
type Context = CrossMslContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
fn from_compilation(
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: MslReflect::try_from(&compile)?,
})
}
}
impl FromCompilation<SpirvCompilation, Naga> for MSL {
type Target = MSL;
type Options = ();
type Context = ();
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
fn from_compilation(
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: NagaReflect::try_from(&compile)?,
})
}
}

View file

@ -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<SPIRV> for WriteSpirV {
})
}
}
/// The context for a SPIRV compilation via Naga
pub struct NagaSpirvContext {
pub fragment: Module,
pub vertex: Module,
}
impl FromCompilation<SpirvCompilation, Naga> for SPIRV {
type Target = SPIRV;
type Options = NagaSpirvOptions;
type Context = NagaSpirvContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
fn from_compilation(
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: NagaReflect::try_from(&compile)?,
})
}
}
pub struct NagaSpirvOptions {
pub lowering: NagaLoweringOptions,
pub version: (u8, u8),
}

View file

@ -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<SpirvCompilation, Naga> for WGSL {
type Target = WGSL;
type Options = WgslCompileOptions;
type Options = NagaLoweringOptions;
type Context = NagaWgslContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context>
+ ReflectShader;
@ -32,98 +23,7 @@ impl FromCompilation<SpirvCompilation, Naga> for WGSL {
compile: SpirvCompilation,
) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
Ok(CompilerBackend {
backend: NagaReflect::create_reflection(&compile)?,
})
}
}
impl CompileShader<WGSL> for NagaReflect {
type Options = WgslCompileOptions;
type Context = NagaWgslContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
fn write_wgsl(module: &Module) -> Result<String, ShaderCompileError> {
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::<naga::FastHashSet<_>>();
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<WGSL> 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,
})

View file

@ -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")]

View file

@ -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<spirv_cross::glsl::Target>;
impl CompileShader<GLSL> for CrossReflect<spirv_cross::glsl::Target> {
type Options = spirv_cross::glsl::Version;
type Context = CrossGlslContext;
fn compile(
mut self,
version: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, 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),
},
},
})
}
}

View file

@ -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<spirv_cross::hlsl::Target>;
impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
type Options = Option<HlslShaderModel>;
type Context = CrossHlslContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, CrossHlslContext>, 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),
},
},
})
}
}

View file

@ -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<hlsl::Target>;
pub(crate) type GlslReflect = CrossReflect<glsl::Target>;
// This is "probably" OK.
unsafe impl<T: Send + spirv_cross::spirv::Target> Send for CrossReflect<T>
where
@ -732,175 +730,13 @@ where
}
}
impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
type Options = glsl::Version;
type Context = CrossGlslContext;
fn compile(
mut self,
version: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, 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<HLSL> for CrossReflect<hlsl::Target> {
type Options = Option<HlslShaderModel>;
type Context = CrossHlslContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, CrossHlslContext>, 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;

View file

@ -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<spirv_cross::msl::Target>;
impl CompileShader<MSL> for CrossReflect<spirv_cross::msl::Target> {
type Options = Option<spirv_cross::msl::Version>;
type Context = CrossMslContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, CrossMslContext>, 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),
},
},
})
}
}

View file

@ -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<Self, error::ShaderReflectError> {
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::<naga::FastHashSet<_>>();
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<Self, Self::Error> {
fn lower_fragment_shader(words: &[u32]) -> Vec<u32> {
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<TypeInfo> {
let (TypeInner::Vector { .. } | TypeInner::Scalar { .. } | TypeInner::Matrix { .. }) = *ty

View file

@ -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<MSL> for NagaReflect {
type Options = ();
type Context = ();
fn compile(
self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
todo!()
}
}

View file

@ -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<SPIRV> for NagaReflect {
type Options = NagaSpirvOptions;
type Context = NagaSpirvContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<Vec<u32>, Self::Context>, ShaderCompileError> {
fn write_spv(
module: &Module,
stage: naga::ShaderStage,
version: (u8, u8),
) -> Result<Vec<u32>, 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,
},
})
}
}

View file

@ -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<WGSL> for NagaReflect {
type Options = NagaLoweringOptions;
type Context = NagaWgslContext;
fn compile(
mut self,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
fn write_wgsl(module: &Module) -> Result<String, ShaderCompileError> {
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,
},
})
}
}

View file

@ -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;

View file

@ -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};

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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<GLuint> {
let (shader, compile_status) = unsafe {

View file

@ -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,
})?;

View file

@ -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;