reflect: port to spirv-cross2

This commit is contained in:
chyyran 2024-09-04 20:49:20 -04:00 committed by Ronny Chan
parent 820fb69328
commit c3033cfbbf
23 changed files with 549 additions and 437 deletions

64
Cargo.lock generated
View file

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

View file

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

View file

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

View file

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

View file

@ -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<spirv_cross::glsl::Target>,
pub artifact: CompiledProgram<spirv_cross2::targets::Glsl>,
}
impl FromCompilation<SpirvCompilation, SpirvCross> for GLSL {

View file

@ -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<spirv_cross::hlsl::Target>,
pub artifact: CompiledProgram<spirv_cross2::targets::Hlsl>,
pub vertex_buffers: HlslBufferAssignments,
pub fragment_buffers: HlslBufferAssignments,
}

View file

@ -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<spirv_cross::msl::Target>,
pub artifact: CompiledProgram<spirv_cross2::targets::Msl>,
}
impl FromCompilation<SpirvCompilation, SpirvCross> for MSL {

View file

@ -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),

View file

@ -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<spirv_cross::glsl::Target>;
use spirv_cross2::compile::CompilableTarget;
use spirv_cross2::reflect::{DecorationValue, ResourceType};
use spirv_cross2::{targets, SpirvCrossError};
impl CompileShader<GLSL> for CrossReflect<spirv_cross::glsl::Target> {
type Options = spirv_cross::glsl::Version;
pub(crate) type GlslReflect = CrossReflect<targets::Glsl>;
impl CompileShader<GLSL> for CrossReflect<targets::Glsl> {
type Options = spirv_cross2::compile::glsl::GlslVersion;
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();
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,
},
},
})

View file

@ -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<spirv_cross::hlsl::Target>;
use spirv_cross2::compile::hlsl::HlslShaderModel;
use spirv_cross2::compile::CompilableTarget;
use spirv_cross2::reflect::{DecorationValue, ResourceType};
use spirv_cross2::{targets, SpirvCrossError};
impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
pub(crate) type HlslReflect = CrossReflect<targets::Hlsl>;
impl CompileShader<HLSL> for CrossReflect<targets::Hlsl> {
type Options = Option<HlslShaderModel>;
type Context = CrossHlslContext;
@ -17,98 +20,107 @@ impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
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;
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,

View file

@ -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<T: Send + spirv_cross::spirv::Target> Send for CrossReflect<T>
where
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{
}
// todo: make this under a mutex
pub(crate) struct CrossReflect<T>
where
T: spirv_cross::spirv::Target,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
T: spirv_cross2::compile::CompilableTarget,
{
vertex: Ast<T>,
fragment: Ast<T>,
}
///The output of the SPIR-V AST after compilation.
///
/// This output is immutable and can not be recompiled later.
pub struct CompiledAst<T: spirv_cross::spirv::Target>(Ast<T>);
impl<T: spirv_cross::spirv::Target> Deref for CompiledAst<T> {
type Target = Ast<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
vertex: Compiler<T>,
fragment: Compiler<T>,
}
/// The compiled SPIR-V program after compilation.
pub struct CompiledProgram<T>
where
T: spirv_cross::spirv::Target,
T: spirv_cross2::compile::CompilableTarget,
{
pub vertex: CompiledAst<T>,
pub fragment: CompiledAst<T>,
pub vertex: CompiledArtifact<T>,
pub fragment: CompiledArtifact<T>,
}
impl ValidateTypeSemantics<Type> for UniqueSemantics {
fn validate_type(&self, ty: &Type) -> Option<TypeInfo> {
let (Type::Float {
ref array,
vecsize,
columns,
..
}
| Type::Int {
ref array,
vecsize,
columns,
..
}
| Type::UInt {
ref array,
vecsize,
columns,
..
}) = *ty
impl ValidateTypeSemantics<TypeInner<'_>> for UniqueSemantics {
fn validate_type(&self, ty: &TypeInner) -> Option<TypeInfo> {
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
}
}
}
impl ValidateTypeSemantics<Type> for TextureSemantics {
fn validate_type(&self, ty: &Type) -> Option<TypeInfo> {
let Type::Float {
ref array,
vecsize,
columns,
..
} = *ty
impl ValidateTypeSemantics<TypeInner<'_>> for TextureSemantics {
fn validate_type(&self, ty: &TypeInner) -> Option<TypeInfo> {
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
}
}
}
impl<T> TryFrom<&SpirvCompilation> for CrossReflect<T>
where
T: spirv_cross::spirv::Target,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
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<T> CrossReflect<T>
where
T: spirv_cross::spirv::Target,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
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,17 +216,56 @@ where
}
// Ensure that vertex attributes use location 0 and 1
let vert_mask = vertex_res.stage_inputs.iter().try_fold(0, |mask, input| {
Ok::<u32, ErrorCode>(
mask | 1 << self.vertex.get_decoration(input.id, Decoration::Location)?,
)
})?;
if vert_mask != 0x3 {
// Verify Vertex inputs
'vertex: {
let entry_points = self.vertex.entry_points()?;
if entry_points.len() != 1 {
return Err(ShaderReflectError::VertexSemanticError(
SemanticsErrorKind::InvalidLocation(vert_mask),
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 {
return Err(ShaderReflectError::VertexSemanticError(
SemanticsErrorKind::InvalidUniformBufferCount(vertex_res.uniform_buffers.len()),
@ -271,17 +297,27 @@ where
impl<T> CrossReflect<T>
where
T: spirv_cross::spirv::Target,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
T: spirv_cross2::compile::CompilableTarget,
{
fn get_ubo_data(
ast: &Ast<T>,
ast: &Compiler<T>,
ubo: &Resource,
blame: SemanticErrorBlame,
) -> Result<UboData, ShaderReflectError> {
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<T>,
ast: &Compiler<T>,
push: &Resource,
blame: SemanticErrorBlame,
) -> Result<u32, ShaderReflectError> {
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<T>,
ast: &Compiler<T>,
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 &parameter.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<Option<BufferReflection<u32>>, 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<TextureData<'a>, 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<Option<BufferReflection<Option<u32>>>, 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<T> ReflectShader for CrossReflect<T>
where
T: spirv_cross::spirv::Target,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
T: spirv_cross2::compile::CompilableTarget,
{
fn reflect(
&mut self,
pass_number: usize,
semantics: &ShaderSemantics,
) -> Result<ShaderReflection, ShaderReflectError> {
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();

View file

@ -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<spirv_cross::msl::Target>;
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<MSL> for CrossReflect<spirv_cross::msl::Target> {
type Options = Option<spirv_cross::msl::Version>;
pub(crate) type MslReflect = CrossReflect<targets::Msl>;
impl CompileShader<MSL> for CrossReflect<targets::Msl> {
type Options = Option<msl::MslVersion>;
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 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<msl::Target>,
stage: ExecutionModel,
binding_map: &mut BTreeMap<ResourceBindingLocation, ResourceBinding>,
ast: &mut Compiler<targets::Msl>,
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)?,
ResourceBinding::Qualified {
set: desc_set,
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);
},
&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);
}

View file

@ -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(),

View file

@ -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<MSL> for NagaReflect {
@ -33,7 +23,7 @@ impl CompileShader<MSL> for NagaReflect {
) -> Result<ShaderCompilerOutput<String, Self::Context>, 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,

View file

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

View file

@ -96,7 +96,7 @@ impl FilterChainD3D9 {
) -> error::Result<Vec<FilterPass>> {
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);

View file

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

View file

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

View file

@ -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<String, CrossGlslContext>,
_cache: bool,
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> {
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())

View file

@ -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<String, CrossGlslContext>,
cache: bool,
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> {
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())

View file

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

View file

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

View file

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