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]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.17.1" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
dependencies = [ dependencies = [
"bytemuck_derive", "bytemuck_derive",
] ]
@ -1678,7 +1678,6 @@ dependencies = [
"ash", "ash",
"gl", "gl",
"librashader", "librashader",
"librashader-spirv-cross",
"objc2 0.5.2", "objc2 0.5.2",
"objc2-metal", "objc2-metal",
"paste", "paste",
@ -1741,13 +1740,13 @@ dependencies = [
"librashader-common", "librashader-common",
"librashader-preprocess", "librashader-preprocess",
"librashader-presets", "librashader-presets",
"librashader-spirv-cross",
"matches", "matches",
"naga", "naga",
"rspirv", "rspirv",
"rustc-hash 2.0.0", "rustc-hash 2.0.0",
"serde", "serde",
"spirv", "spirv",
"spirv-cross2",
"spirv-to-dxil", "spirv-to-dxil",
"thiserror", "thiserror",
] ]
@ -1842,8 +1841,8 @@ dependencies = [
"librashader-presets", "librashader-presets",
"librashader-reflect", "librashader-reflect",
"librashader-runtime", "librashader-runtime",
"librashader-spirv-cross",
"rayon", "rayon",
"spirv-cross2",
"sptr", "sptr",
"thiserror", "thiserror",
] ]
@ -1914,18 +1913,6 @@ dependencies = [
"winit", "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]] [[package]]
name = "libredox" name = "libredox"
version = "0.0.2" version = "0.0.2"
@ -2936,9 +2923,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.35" version = "0.38.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"errno", "errno",
@ -3147,6 +3134,45 @@ dependencies = [
"bitflags 2.6.0", "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]] [[package]]
name = "spirv-to-dxil" name = "spirv-to-dxil"
version = "0.4.7" version = "0.4.7"

View file

@ -20,8 +20,7 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
windows = "0.58.0" windows = "0.58.0"
ash = "0.38" 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-metal = { version = "0.2" }
objc2 = { version = "0.5.0" } objc2 = { version = "0.5.0" }

View file

@ -42,7 +42,6 @@ rustc-hash = "2.0.0"
sptr = "0.3.2" sptr = "0.3.2"
ash = { workspace = true, optional = true } ash = { workspace = true, optional = true }
spirv_cross = { workspace = true }
[dependencies.librashader] [dependencies.librashader]
path = "../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-preprocess = { path = "../librashader-preprocess", version = "0.3.3" }
librashader-presets = { path = "../librashader-presets", 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 } naga = { version = "22", optional = true }
rspirv = { version = "0.12.0", optional = true } rspirv = { version = "0.12.0", optional = true }
@ -40,11 +40,11 @@ optional = true
[features] [features]
default = ["cross", "naga", "serialize", "wgsl", "msl"] default = ["cross", "naga", "serialize", "wgsl", "msl"]
dxil = ["spirv_cross/hlsl", "spirv-to-dxil"] dxil = ["spirv-cross2/hlsl", "dep:spirv-to-dxil"]
wgsl = ["cross", "naga/wgsl-out", "spirv", "rspirv"] wgsl = ["cross", "naga/wgsl-out", "dep:spirv", "dep:rspirv"]
cross = [ "spirv_cross", "spirv_cross/glsl", "spirv_cross/hlsl", "spirv_cross/msl" ] cross = [ "dep:spirv-cross2", "spirv-cross2/glsl", "spirv-cross2/hlsl", "spirv-cross2/msl" ]
naga = [ "rspirv", "spirv", "naga/spv-in", "naga/spv-out", "naga/wgsl-out", "naga/msl-out" ] naga = [ "dep:rspirv", "dep:spirv", "naga/spv-in", "naga/spv-out", "naga/wgsl-out", "naga/msl-out" ]
serialize = [ "serde" ] serialize = [ "dep:serde" ]
msl = [ "spirv_cross/msl", "naga/msl-out" ] msl = [ "spirv-cross2/msl", "naga/msl-out" ]
unstable-naga-in = ["naga/glsl-in"] unstable-naga-in = ["naga/glsl-in"]

View file

@ -6,7 +6,7 @@ use crate::reflect::cross::{CompiledProgram, SpirvCross};
use crate::reflect::ReflectShader; use crate::reflect::ReflectShader;
/// The GLSL version to target. /// 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; use crate::reflect::cross::glsl::GlslReflect;
@ -15,7 +15,7 @@ pub struct CrossGlslContext {
/// A map of bindings of sampler names to binding locations. /// A map of bindings of sampler names to binding locations.
pub sampler_bindings: Vec<(String, u32)>, pub sampler_bindings: Vec<(String, u32)>,
/// The compiled program artifact after compilation. /// 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 { impl FromCompilation<SpirvCompilation, SpirvCross> for GLSL {

View file

@ -7,7 +7,7 @@ use crate::reflect::cross::{CompiledProgram, SpirvCross};
use crate::reflect::ReflectShader; use crate::reflect::ReflectShader;
/// The HLSL shader model version to target. /// 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 /// Buffer assignment information
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -99,7 +99,7 @@ impl HlslBufferAssignments {
/// The context for a HLSL compilation via spirv-cross. /// The context for a HLSL compilation via spirv-cross.
pub struct CrossHlslContext { pub struct CrossHlslContext {
/// The compiled HLSL program. /// The compiled HLSL program.
pub artifact: CompiledProgram<spirv_cross::hlsl::Target>, pub artifact: CompiledProgram<spirv_cross2::targets::Hlsl>,
pub vertex_buffers: HlslBufferAssignments, pub vertex_buffers: HlslBufferAssignments,
pub fragment_buffers: HlslBufferAssignments, pub fragment_buffers: HlslBufferAssignments,
} }

View file

@ -9,8 +9,8 @@ use crate::reflect::ReflectShader;
use naga::back::msl::TranslationInfo; use naga::back::msl::TranslationInfo;
use naga::Module; use naga::Module;
/// The HLSL shader model version to target. /// The MSL language version to target.
pub use spirv_cross::msl::Version as MslVersion; pub use spirv_cross2::compile::msl::MslVersion;
/// Compiler options for MSL /// Compiler options for MSL
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -22,7 +22,7 @@ pub struct MslNagaCompileOptions {
/// The context for a MSL compilation via spirv-cross. /// The context for a MSL compilation via spirv-cross.
pub struct CrossMslContext { pub struct CrossMslContext {
/// The compiled HLSL program. /// The compiled HLSL program.
pub artifact: CompiledProgram<spirv_cross::msl::Target>, pub artifact: CompiledProgram<spirv_cross2::targets::Msl>,
} }
impl FromCompilation<SpirvCompilation, SpirvCross> for MSL { impl FromCompilation<SpirvCompilation, SpirvCross> for MSL {

View file

@ -20,7 +20,7 @@ pub enum ShaderCompileError {
/// Error when transpiling from spirv-cross. /// Error when transpiling from spirv-cross.
#[error("spirv-cross error: {0:?}")] #[error("spirv-cross error: {0:?}")]
SpirvCrossCompileError(#[from] spirv_cross::ErrorCode), SpirvCrossCompileError(#[from] spirv_cross2::SpirvCrossError),
/// Error when transpiling from spirv-to-dxil /// Error when transpiling from spirv-to-dxil
#[cfg(all(target_os = "windows", feature = "dxil"))] #[cfg(all(target_os = "windows", feature = "dxil"))]
@ -87,7 +87,7 @@ pub enum SemanticsErrorKind {
pub enum ShaderReflectError { pub enum ShaderReflectError {
/// Reflection error from spirv-cross. /// Reflection error from spirv-cross.
#[error("spirv cross error: {0}")] #[error("spirv cross error: {0}")]
SpirvCrossError(#[from] spirv_cross::ErrorCode), SpirvCrossError(#[from] spirv_cross2::SpirvCrossError),
/// Error when validating vertex shader semantics. /// Error when validating vertex shader semantics.
#[error("error when verifying vertex semantics: {0:?}")] #[error("error when verifying vertex semantics: {0:?}")]
VertexSemanticError(SemanticsErrorKind), VertexSemanticError(SemanticsErrorKind),

View file

@ -2,136 +2,165 @@ use crate::back::glsl::CrossGlslContext;
use crate::back::targets::GLSL; use crate::back::targets::GLSL;
use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::back::{CompileShader, ShaderCompilerOutput};
use crate::error::ShaderCompileError; use crate::error::ShaderCompileError;
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; use crate::reflect::cross::{CompiledProgram, CrossReflect};
use spirv_cross::spirv::Decoration; use spirv::Decoration;
use spirv_cross::ErrorCode;
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> { pub(crate) type GlslReflect = CrossReflect<targets::Glsl>;
type Options = spirv_cross::glsl::Version;
impl CompileShader<GLSL> for CrossReflect<targets::Glsl> {
type Options = spirv_cross2::compile::glsl::GlslVersion;
type Context = CrossGlslContext; type Context = CrossGlslContext;
fn compile( fn compile(
mut self, mut self,
version: Self::Options, version: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> { ) -> 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.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)?; options.es_default_float_precision_highp = true;
self.fragment.set_compiler_options(&options)?; options.es_default_int_precision_highp = true;
options.enable_420pack_extension = false;
let vertex_resources = self.vertex.get_shader_resources()?; let vertex_resources = self.vertex.shader_resources()?;
let fragment_resources = self.fragment.get_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)?; // let location = self.vertex.get_decoration(res.id, Decoration::Location)?;
// self.vertex // self.vertex
// .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?; // .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)?; // let location = self.fragment.get_decoration(res.id, Decoration::Location)?;
// self.fragment // self.fragment
// .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?; // .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?;
self.fragment 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer", "Cannot have more than one push constant buffer",
)), )),
)); ));
} }
for res in &vertex_resources.push_constant_buffers { for res in vertex_pcb {
self.vertex.set_name(res.id, "LIBRA_PUSH_VERTEX_INSTANCE")?;
self.vertex 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 // todo: options
let _flatten = false; 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer", "Cannot have more than one uniform buffer",
)), )),
)); ));
} }
for res in &vertex_resources.uniform_buffers { for res in vertex_ubo {
// if flatten { // if flatten {
// self.vertex.flatten_buffer_block(res.id)?; // self.vertex.flatten_buffer_block(res.id)?;
// } // }
self.vertex.set_name(res.id, "LIBRA_UBO_VERTEX_INSTANCE")?; self.vertex.set_name(res.id, c"LIBRA_UBO_VERTEX_INSTANCE")?;
self.vertex.set_name(res.base_type_id, "LIBRA_UBO_VERTEX")?;
self.vertex self.vertex
.unset_decoration(res.id, Decoration::DescriptorSet)?; .set_name(res.base_type_id, c"LIBRA_UBO_VERTEX")?;
self.vertex.unset_decoration(res.id, Decoration::Binding)?; 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer", "Cannot have more than one push constant buffer",
)), )),
)); ));
} }
for res in &fragment_resources.push_constant_buffers {
for res in fragment_pcb {
self.fragment self.fragment
.set_name(res.id, "LIBRA_PUSH_FRAGMENT_INSTANCE")?; .set_name(res.id, c"LIBRA_PUSH_FRAGMENT_INSTANCE")?;
self.fragment 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer", "Cannot have more than one uniform buffer",
)), )),
)); ));
} }
for res in &fragment_resources.uniform_buffers { for res in fragment_ubo {
// if flatten { // if flatten {
// self.fragment.flatten_buffer_block(res.id)?; // self.fragment.flatten_buffer_block(res.id)?;
// } // }
self.fragment self.fragment
.set_name(res.id, "LIBRA_UBO_FRAGMENT_INSTANCE")?; .set_name(res.id, c"LIBRA_UBO_FRAGMENT_INSTANCE")?;
self.fragment 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 self.fragment
.unset_decoration(res.id, Decoration::DescriptorSet)?; .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?;
self.fragment
.unset_decoration(res.id, Decoration::Binding)?;
} }
let mut texture_fixups = Vec::new(); 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 self.fragment
.unset_decoration(res.id, Decoration::DescriptorSet)?; .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?;
self.fragment let mut name = res.name.to_string();
.unset_decoration(res.id, Decoration::Binding)?;
let mut name = res.name;
name.push('\0'); name.push('\0');
texture_fixups.push((name, binding)); texture_fixups.push((name, binding));
} }
let vertex_compiled = self.vertex.compile(&options)?;
let fragment_compiled = self.fragment.compile(&options)?;
Ok(ShaderCompilerOutput { Ok(ShaderCompilerOutput {
vertex: self.vertex.compile()?, vertex: vertex_compiled.to_string(),
fragment: self.fragment.compile()?, fragment: fragment_compiled.to_string(),
context: CrossGlslContext { context: CrossGlslContext {
sampler_bindings: texture_fixups, sampler_bindings: texture_fixups,
artifact: CompiledProgram { artifact: CompiledProgram {
vertex: CompiledAst(self.vertex), vertex: vertex_compiled,
fragment: CompiledAst(self.fragment), fragment: fragment_compiled,
}, },
}, },
}) })

View file

@ -2,14 +2,17 @@ use crate::back::hlsl::{CrossHlslContext, HlslBufferAssignment, HlslBufferAssign
use crate::back::targets::HLSL; use crate::back::targets::HLSL;
use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::back::{CompileShader, ShaderCompilerOutput};
use crate::error::ShaderCompileError; use crate::error::ShaderCompileError;
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; use crate::reflect::cross::{CompiledProgram, CrossReflect};
use spirv_cross::hlsl::ShaderModel as HlslShaderModel; use spirv::Decoration;
use spirv_cross::spirv::Decoration;
use spirv_cross::ErrorCode;
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 Options = Option<HlslShaderModel>;
type Context = CrossHlslContext; type Context = CrossHlslContext;
@ -17,98 +20,107 @@ impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
mut self, mut self,
options: Self::Options, options: Self::Options,
) -> Result<ShaderCompilerOutput<String, CrossHlslContext>, ShaderCompileError> { ) -> Result<ShaderCompilerOutput<String, CrossHlslContext>, ShaderCompileError> {
let sm = options.unwrap_or(HlslShaderModel::V5_0); let sm = options.unwrap_or(HlslShaderModel::ShaderModel5_0);
let mut options = spirv_cross::hlsl::CompilerOptions::default();
options.shader_model = sm;
self.vertex.set_compiler_options(&options)?; let mut options = targets::Hlsl::options();
self.fragment.set_compiler_options(&options)?; options.shader_model = sm;
// todo: options // todo: options
let vertex_resources = self.vertex.get_shader_resources()?; let vertex_resources = self.vertex.shader_resources()?;
let fragment_resources = self.fragment.get_shader_resources()?; let fragment_resources = self.fragment.shader_resources()?;
let mut vertex_buffer_assignment = HlslBufferAssignments::default(); let mut vertex_buffer_assignment = HlslBufferAssignments::default();
let mut fragment_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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer", "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 { vertex_buffer_assignment.ubo = Some(HlslBufferAssignment {
name: buf.name.clone(), name: buf.name.to_string(),
id: buf.id, 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer", "Cannot have more than one push constant buffer",
)), )),
)); ));
} }
if let Some(buf) = vertex_pcb.next() {
if let Some(buf) = vertex_resources.push_constant_buffers.first() {
vertex_buffer_assignment.push = Some(HlslBufferAssignment { vertex_buffer_assignment.push = Some(HlslBufferAssignment {
name: buf.name.clone(), name: buf.name.to_string(),
id: buf.id, 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer", "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 { fragment_buffer_assignment.ubo = Some(HlslBufferAssignment {
name: buf.name.clone(), name: buf.name.to_string(),
id: buf.id, 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( return Err(ShaderCompileError::SpirvCrossCompileError(
ErrorCode::CompilationError(String::from( SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer", "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 { fragment_buffer_assignment.push = Some(HlslBufferAssignment {
name: buf.name.clone(), name: buf.name.to_string(),
id: buf.id, id: buf.id.id(),
}) })
} }
if sm == HlslShaderModel::V3_0 { if sm == HlslShaderModel::ShaderModel3_0 {
for res in &fragment_resources.sampled_images { for res in fragment_resources.resources_for_type(ResourceType::SampledImage)? {
let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?; let Some(DecorationValue::Literal(binding)) =
self.fragment.decoration(res.id, Decoration::Binding)?
else {
continue;
};
self.fragment self.fragment
.set_name(res.id, &format!("LIBRA_SAMPLER2D_{binding}"))?; .set_name(res.id, format!("LIBRA_SAMPLER2D_{binding}"))?;
// self.fragment // self.fragment
// .unset_decoration(res.id, Decoration::Binding)?; // .unset_decoration(res.id, Decoration::Binding)?;
} }
} }
let vertex_compiled = self.vertex.compile(&options)?;
let fragment_compiled = self.fragment.compile(&options)?;
Ok(ShaderCompilerOutput { Ok(ShaderCompilerOutput {
vertex: self.vertex.compile()?, vertex: vertex_compiled.to_string(),
fragment: self.fragment.compile()?, fragment: fragment_compiled.to_string(),
context: CrossHlslContext { context: CrossHlslContext {
artifact: CompiledProgram { artifact: CompiledProgram {
vertex: CompiledAst(self.vertex), vertex: vertex_compiled,
fragment: CompiledAst(self.fragment), fragment: fragment_compiled,
}, },
vertex_buffers: vertex_buffer_assignment, vertex_buffers: vertex_buffer_assignment,

View file

@ -9,6 +9,7 @@ pub mod msl;
use crate::error::{SemanticsErrorKind, ShaderReflectError}; use crate::error::{SemanticsErrorKind, ShaderReflectError};
use crate::front::SpirvCompilation; use crate::front::SpirvCompilation;
use crate::reflect::helper::{SemanticErrorBlame, TextureData, UboData};
use crate::reflect::semantics::{ use crate::reflect::semantics::{
BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderReflection, ShaderSemantics, BindingMeta, BindingStage, BufferReflection, MemberOffset, ShaderReflection, ShaderSemantics,
TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo,
@ -16,13 +17,15 @@ use crate::reflect::semantics::{
MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
}; };
use crate::reflect::{align_uniform_size, ReflectShader}; 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 librashader_common::map::ShortString;
use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type}; use spirv_cross2::compile::CompiledArtifact;
use spirv_cross::ErrorCode; 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. /// Reflect shaders under SPIRV-Cross semantics.
/// ///
@ -30,135 +33,115 @@ use spirv_cross::ErrorCode;
#[derive(Debug)] #[derive(Debug)]
pub struct SpirvCross; pub struct SpirvCross;
// This is "probably" OK. // todo: make this under a mutex
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>,
{
}
pub(crate) struct CrossReflect<T> pub(crate) struct CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{ {
vertex: Ast<T>, vertex: Compiler<T>,
fragment: Ast<T>, fragment: Compiler<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
}
} }
/// The compiled SPIR-V program after compilation. /// The compiled SPIR-V program after compilation.
pub struct CompiledProgram<T> pub struct CompiledProgram<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
{ {
pub vertex: CompiledAst<T>, pub vertex: CompiledArtifact<T>,
pub fragment: CompiledAst<T>, pub fragment: CompiledArtifact<T>,
} }
impl ValidateTypeSemantics<Type> for UniqueSemantics { impl ValidateTypeSemantics<TypeInner<'_>> for UniqueSemantics {
fn validate_type(&self, ty: &Type) -> Option<TypeInfo> { fn validate_type(&self, ty: &TypeInner) -> Option<TypeInfo> {
let (Type::Float { let (TypeInner::Vector { .. } | TypeInner::Scalar { .. } | TypeInner::Matrix { .. }) = *ty
ref array,
vecsize,
columns,
..
}
| Type::Int {
ref array,
vecsize,
columns,
..
}
| Type::UInt {
ref array,
vecsize,
columns,
..
}) = *ty
else { else {
return None; return None;
}; };
if !array.is_empty() { match self {
return None;
}
let valid = match self {
UniqueSemantics::MVP => { 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::FrameCount
| UniqueSemantics::Rotation | UniqueSemantics::Rotation
| UniqueSemantics::TotalSubFrames | UniqueSemantics::CurrentSubFrame
| UniqueSemantics::CurrentSubFrame => { | UniqueSemantics::TotalSubFrames => {
matches!(ty, Type::UInt { .. }) && vecsize == 1 && columns == 1 // 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 => { 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 => { UniqueSemantics::FloatParameter => {
matches!(ty, Type::Float { .. }) && vecsize == 1 && columns == 1 // Float32 == width 4
if matches!(ty, TypeInner::Scalar( Scalar { kind, size }) if *kind == ScalarKind::Float && *size == BitWidth::Word)
{
return Some(TypeInfo {
size: 1,
columns: 1,
});
}
}
_ => {
if matches!(ty, TypeInner::Vector { scalar: Scalar { size, kind }, width: vecwidth, .. }
if *kind == ScalarKind::Float && *size == BitWidth::Word && *vecwidth == 4)
{
return Some(TypeInfo {
size: 4,
columns: 1,
});
}
} }
_ => matches!(ty, Type::Float { .. }) && vecsize == 4 && columns == 1,
}; };
if valid {
Some(TypeInfo {
size: vecsize,
columns,
})
} else {
None None
} }
} }
}
impl ValidateTypeSemantics<Type> for TextureSemantics { impl ValidateTypeSemantics<TypeInner<'_>> for TextureSemantics {
fn validate_type(&self, ty: &Type) -> Option<TypeInfo> { fn validate_type(&self, ty: &TypeInner) -> Option<TypeInfo> {
let Type::Float { let TypeInner::Vector {
ref array, scalar: Scalar { size, kind },
vecsize, width: vecwidth,
columns, } = ty
..
} = *ty
else { else {
return None; return None;
}; };
if !array.is_empty() { if *kind == ScalarKind::Float && *size == BitWidth::Word && *vecwidth == 4 {
return None; return Some(TypeInfo {
size: 4,
columns: 1,
});
} }
if vecsize == 4 && columns == 1 {
Some(TypeInfo {
size: vecsize,
columns,
})
} else {
None None
} }
} }
}
impl<T> TryFrom<&SpirvCompilation> for CrossReflect<T> impl<T> TryFrom<&SpirvCompilation> for CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{ {
type Error = ShaderReflectError; type Error = ShaderReflectError;
@ -166,8 +149,8 @@ where
let vertex_module = Module::from_words(&value.vertex); let vertex_module = Module::from_words(&value.vertex);
let fragment_module = Module::from_words(&value.fragment); let fragment_module = Module::from_words(&value.fragment);
let vertex = Ast::parse(&vertex_module)?; let vertex = Compiler::new(vertex_module)?;
let fragment = Ast::parse(&fragment_module)?; let fragment = Compiler::new(fragment_module)?;
Ok(CrossReflect { vertex, fragment }) Ok(CrossReflect { vertex, fragment })
} }
@ -175,14 +158,12 @@ where
impl<T> CrossReflect<T> impl<T> CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{ {
fn validate( fn validate(
&self, &self,
vertex_res: &ShaderResources, vertex_res: &AllResources,
fragment_res: &ShaderResources, fragment_res: &AllResources,
) -> Result<(), ShaderReflectError> { ) -> Result<(), ShaderReflectError> {
if !vertex_res.sampled_images.is_empty() if !vertex_res.sampled_images.is_empty()
|| !vertex_res.storage_buffers.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 .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 { if fragment_location != 0 {
return Err(ShaderReflectError::FragmentSemanticError( return Err(ShaderReflectError::FragmentSemanticError(
SemanticsErrorKind::InvalidLocation(fragment_location), SemanticsErrorKind::InvalidLocation(fragment_location),
@ -229,17 +216,56 @@ where
} }
// Ensure that vertex attributes use location 0 and 1 // Ensure that vertex attributes use location 0 and 1
let vert_mask = vertex_res.stage_inputs.iter().try_fold(0, |mask, input| { // Verify Vertex inputs
Ok::<u32, ErrorCode>( 'vertex: {
mask | 1 << self.vertex.get_decoration(input.id, Decoration::Location)?, let entry_points = self.vertex.entry_points()?;
) if entry_points.len() != 1 {
})?;
if vert_mask != 0x3 {
return Err(ShaderReflectError::VertexSemanticError( 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 { if vertex_res.uniform_buffers.len() > 1 {
return Err(ShaderReflectError::VertexSemanticError( return Err(ShaderReflectError::VertexSemanticError(
SemanticsErrorKind::InvalidUniformBufferCount(vertex_res.uniform_buffers.len()), SemanticsErrorKind::InvalidUniformBufferCount(vertex_res.uniform_buffers.len()),
@ -271,17 +297,27 @@ where
impl<T> CrossReflect<T> impl<T> CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{ {
fn get_ubo_data( fn get_ubo_data(
ast: &Ast<T>, ast: &Compiler<T>,
ubo: &Resource, ubo: &Resource,
blame: SemanticErrorBlame, blame: SemanticErrorBlame,
) -> Result<UboData, ShaderReflectError> { ) -> Result<UboData, ShaderReflectError> {
let descriptor_set = ast.get_decoration(ubo.id, Decoration::DescriptorSet)?; let Some(descriptor_set) = ast
let binding = ast.get_decoration(ubo.id, Decoration::Binding)?; .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 { if binding >= MAX_BINDINGS_COUNT {
return Err(blame.error(SemanticsErrorKind::InvalidBinding(binding))); return Err(blame.error(SemanticsErrorKind::InvalidBinding(binding)));
} }
@ -289,21 +325,19 @@ where
return Err(blame.error(SemanticsErrorKind::InvalidDescriptorSet(descriptor_set))); return Err(blame.error(SemanticsErrorKind::InvalidDescriptorSet(descriptor_set)));
} }
let size = ast.get_declared_struct_size(ubo.base_type_id)?; let size = ast.type_description(ubo.base_type_id)?.size_hint.declared() as u32;
Ok(UboData { Ok(UboData { binding, size })
// descriptor_set,
// id: ubo.id,
binding,
size,
})
} }
fn get_push_size( fn get_push_size(
ast: &Ast<T>, ast: &Compiler<T>,
push: &Resource, push: &Resource,
blame: SemanticErrorBlame, blame: SemanticErrorBlame,
) -> Result<u32, ShaderReflectError> { ) -> 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 { if size > MAX_PUSH_BUFFER_SIZE {
return Err(blame.error(SemanticsErrorKind::InvalidPushBufferSize(size))); return Err(blame.error(SemanticsErrorKind::InvalidPushBufferSize(size)));
} }
@ -311,7 +345,7 @@ where
} }
fn reflect_buffer_range_metas( fn reflect_buffer_range_metas(
ast: &Ast<T>, ast: &Compiler<T>,
resource: &Resource, resource: &Resource,
pass_number: usize, pass_number: usize,
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
@ -319,24 +353,30 @@ where
offset_type: UniformMemberBlock, offset_type: UniformMemberBlock,
blame: SemanticErrorBlame, blame: SemanticErrorBlame,
) -> Result<(), ShaderReflectError> { ) -> Result<(), ShaderReflectError> {
let ranges = ast.get_active_buffer_ranges(resource.id)?; let ranges = ast.active_buffer_ranges(resource.id)?;
for range in ranges { for range in ranges {
let name = ast.get_member_name(resource.base_type_id, range.index)?; let Some(name) = ast.member_name(resource.base_type_id, range.index)? else {
let ubo_type = ast.get_type(resource.base_type_id)?; // member has no name!
let range_type = match ubo_type { return Err(blame.error(SemanticsErrorKind::InvalidRange(range.index)));
Type::Struct { member_types, .. } => { };
let range_type = member_types
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) .get(range.index as usize)
.cloned()
.ok_or(blame.error(SemanticsErrorKind::InvalidRange(range.index)))?; .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)), _ => return Err(blame.error(SemanticsErrorKind::InvalidResourceType)),
}; };
if let Some(parameter) = semantics.uniform_semantics.get_unique_semantic(&name) { if let Some(parameter) = semantics.uniform_semantics.unique_semantic(&name) {
let Some(typeinfo) = parameter.semantics.validate_type(&range_type) else { let Some(typeinfo) = parameter.semantics.validate_type(&range_type.inner) else {
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name))); return Err(
blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name.to_string()))
);
}; };
match &parameter.semantics { match &parameter.semantics {
@ -347,7 +387,7 @@ where
&& expected != offset && expected != offset
{ {
return Err(ShaderReflectError::MismatchedOffset { return Err(ShaderReflectError::MismatchedOffset {
semantic: name, semantic: name.to_string(),
expected, expected,
received: offset, received: offset,
ty: offset_type, ty: offset_type,
@ -356,7 +396,7 @@ where
} }
if meta.size != typeinfo.size { if meta.size != typeinfo.size {
return Err(ShaderReflectError::MismatchedSize { return Err(ShaderReflectError::MismatchedSize {
semantic: name, semantic: name.to_string(),
vertex: meta.size, vertex: meta.size,
fragment: typeinfo.size, fragment: typeinfo.size,
pass: pass_number, pass: pass_number,
@ -365,7 +405,7 @@ where
*meta.offset.offset_mut(offset_type) = Some(offset); *meta.offset.offset_mut(offset_type) = Some(offset);
} else { } else {
let name = ShortString::from(name); let name = ShortString::from(name.as_ref());
meta.parameter_meta.insert( meta.parameter_meta.insert(
name.clone(), name.clone(),
VariableMeta { VariableMeta {
@ -383,7 +423,7 @@ where
&& expected != offset && expected != offset
{ {
return Err(ShaderReflectError::MismatchedOffset { return Err(ShaderReflectError::MismatchedOffset {
semantic: name, semantic: name.to_string(),
expected, expected,
received: offset, received: offset,
ty: offset_type, ty: offset_type,
@ -392,7 +432,7 @@ where
} }
if meta.size != typeinfo.size * typeinfo.columns { if meta.size != typeinfo.size * typeinfo.columns {
return Err(ShaderReflectError::MismatchedSize { return Err(ShaderReflectError::MismatchedSize {
semantic: name, semantic: name.to_string(),
vertex: meta.size, vertex: meta.size,
fragment: typeinfo.size, fragment: typeinfo.size,
pass: pass_number, pass: pass_number,
@ -404,7 +444,7 @@ where
meta.unique_meta.insert( meta.unique_meta.insert(
*semantics, *semantics,
VariableMeta { VariableMeta {
id: name.into(), id: ShortString::from(name.as_ref()),
offset: MemberOffset::new(offset, offset_type), offset: MemberOffset::new(offset, offset_type),
size: typeinfo.size * typeinfo.columns, size: typeinfo.size * typeinfo.columns,
}, },
@ -412,9 +452,11 @@ where
} }
} }
} }
} else if let Some(texture) = semantics.uniform_semantics.get_texture_semantic(&name) { } else if let Some(texture) = semantics.uniform_semantics.texture_semantic(&name) {
let Some(_typeinfo) = texture.semantics.validate_type(&range_type) else { let Some(_typeinfo) = texture.semantics.validate_type(&range_type.inner) else {
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name))); return Err(
blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name.to_string()))
);
}; };
if let TextureSemantics::PassOutput = texture.semantics { if let TextureSemantics::PassOutput = texture.semantics {
@ -432,7 +474,7 @@ where
&& expected != offset && expected != offset
{ {
return Err(ShaderReflectError::MismatchedOffset { return Err(ShaderReflectError::MismatchedOffset {
semantic: name, semantic: name.to_string(),
expected, expected,
received: offset, received: offset,
ty: offset_type, ty: offset_type,
@ -455,12 +497,12 @@ where
SemanticErrorBlame::Vertex => BindingStage::VERTEX, SemanticErrorBlame::Vertex => BindingStage::VERTEX,
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT, SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
}, },
id: ShortString::from(name), id: ShortString::from(name.as_ref()),
}, },
); );
} }
} else { } else {
return Err(blame.error(SemanticsErrorKind::UnknownSemantics(name))); return Err(blame.error(SemanticsErrorKind::UnknownSemantics(name.to_string())));
} }
} }
Ok(()) Ok(())
@ -473,12 +515,12 @@ where
) -> Result<Option<BufferReflection<u32>>, ShaderReflectError> { ) -> Result<Option<BufferReflection<u32>>, ShaderReflectError> {
if let Some(vertex_ubo) = vertex_ubo { if let Some(vertex_ubo) = vertex_ubo {
self.vertex 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 { if let Some(fragment_ubo) = fragment_ubo {
self.fragment self.fragment
.set_decoration(fragment_ubo.id, Decoration::Binding, 0)?; .set_decoration(fragment_ubo.id, Decoration::Binding, Some(0))?;
} }
match (vertex_ubo, fragment_ubo) { match (vertex_ubo, fragment_ubo) {
@ -530,10 +572,7 @@ where
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
meta: &mut BindingMeta, meta: &mut BindingMeta,
) -> Result<(), ShaderReflectError> { ) -> Result<(), ShaderReflectError> {
let Some(semantic) = semantics let Some(semantic) = semantics.texture_semantics.texture_semantic(texture.name) else {
.texture_semantics
.get_texture_semantic(texture.name)
else {
return Err( return Err(
SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics( SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics(
texture.name.to_string(), texture.name.to_string(),
@ -561,12 +600,25 @@ where
&'a self, &'a self,
texture: &'a Resource, texture: &'a Resource,
) -> Result<TextureData<'a>, ShaderReflectError> { ) -> Result<TextureData<'a>, ShaderReflectError> {
let descriptor_set = self let Some(descriptor_set) = self
.fragment .fragment
.get_decoration(texture.id, Decoration::DescriptorSet)?; .decoration(texture.id, Decoration::DescriptorSet)?
let binding = self .and_then(|l| l.as_literal())
else {
return Err(ShaderReflectError::FragmentSemanticError(
SemanticsErrorKind::MissingBinding,
));
};
let Some(binding) = self
.fragment .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 { if descriptor_set != 0 {
return Err(ShaderReflectError::FragmentSemanticError( return Err(ShaderReflectError::FragmentSemanticError(
SemanticsErrorKind::InvalidDescriptorSet(descriptor_set), SemanticsErrorKind::InvalidDescriptorSet(descriptor_set),
@ -593,12 +645,12 @@ where
) -> Result<Option<BufferReflection<Option<u32>>>, ShaderReflectError> { ) -> Result<Option<BufferReflection<Option<u32>>>, ShaderReflectError> {
if let Some(vertex_pcb) = vertex_pcb { if let Some(vertex_pcb) = vertex_pcb {
self.vertex 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 { if let Some(fragment_pcb) = fragment_pcb {
self.fragment self.fragment
.set_decoration(fragment_pcb.id, Decoration::Binding, 1)?; .set_decoration(fragment_pcb.id, Decoration::Binding, Some(1))?;
} }
match (vertex_pcb, fragment_pcb) { match (vertex_pcb, fragment_pcb) {
@ -647,17 +699,15 @@ where
impl<T> ReflectShader for CrossReflect<T> impl<T> ReflectShader for CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross2::compile::CompilableTarget,
Ast<T>: spirv_cross::spirv::Compile<T>,
Ast<T>: spirv_cross::spirv::Parse<T>,
{ {
fn reflect( fn reflect(
&mut self, &mut self,
pass_number: usize, pass_number: usize,
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
) -> Result<ShaderReflection, ShaderReflectError> { ) -> Result<ShaderReflection, ShaderReflectError> {
let vertex_res = self.vertex.get_shader_resources()?; let vertex_res = self.vertex.shader_resources()?.all_resources()?;
let fragment_res = self.fragment.get_shader_resources()?; let fragment_res = self.fragment.shader_resources()?.all_resources()?;
self.validate(&vertex_res, &fragment_res)?; self.validate(&vertex_res, &fragment_res)?;
let vertex_ubo = vertex_res.uniform_buffers.first(); 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::targets::MSL;
use crate::back::{CompileShader, ShaderCompilerOutput}; use crate::back::{CompileShader, ShaderCompilerOutput};
use crate::error::ShaderCompileError; use crate::error::ShaderCompileError;
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect}; use crate::reflect::cross::{CompiledProgram, CrossReflect};
use spirv_cross::msl;
use spirv_cross::msl::{ResourceBinding, ResourceBindingLocation};
use spirv_cross::spirv::{Ast, Decoration, ExecutionModel};
use std::collections::BTreeMap;
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> { pub(crate) type MslReflect = CrossReflect<targets::Msl>;
type Options = Option<spirv_cross::msl::Version>;
impl CompileShader<MSL> for CrossReflect<targets::Msl> {
type Options = Option<msl::MslVersion>;
type Context = CrossMslContext; type Context = CrossMslContext;
fn compile( fn compile(
mut self, mut self,
options: Self::Options, options: Self::Options,
) -> Result<ShaderCompilerOutput<String, CrossMslContext>, ShaderCompileError> { ) -> Result<ShaderCompilerOutput<String, CrossMslContext>, ShaderCompileError> {
let version = options.unwrap_or(msl::Version::V2_0); let version = options.unwrap_or(msl::MslVersion::new(2, 0, 0));
let mut vert_options = spirv_cross::msl::CompilerOptions::default(); let mut options = targets::Msl::options();
let mut frag_options = spirv_cross::msl::CompilerOptions::default(); options.version = version;
vert_options.version = version;
frag_options.version = version;
fn set_bindings( fn set_bindings(
ast: &Ast<msl::Target>, ast: &mut Compiler<targets::Msl>,
stage: ExecutionModel, stage: spirv::ExecutionModel,
binding_map: &mut BTreeMap<ResourceBindingLocation, ResourceBinding>,
) -> Result<(), ShaderCompileError> { ) -> Result<(), ShaderCompileError> {
let resources = ast.get_shader_resources()?; let resources = ast.shader_resources()?;
for resource in &resources.push_constant_buffers { for resource in resources.resources_for_type(ResourceType::PushConstant)? {
let location = ResourceBindingLocation { let Some(DecorationValue::Literal(buffer)) =
stage, ast.decoration(resource.id, Decoration::Binding)?
desc_set: msl::PUSH_CONSTANT_DESCRIPTOR_SET, else {
binding: msl::PUSH_CONSTANT_BINDING, continue;
};
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
}; };
binding_map.insert(location, overridden); ast.add_resource_binding(
stage,
ResourceBinding::PushConstantBuffer,
&BindTarget {
buffer,
texture: 0,
sampler: 0,
count: None,
},
)?
} }
for resource in resources let ubos = resources.resources_for_type(ResourceType::UniformBuffer)?;
.uniform_buffers let sampled = resources.resources_for_type(ResourceType::SampledImage)?;
.iter()
.chain(resources.sampled_images.iter()) for resource in ubos.chain(sampled) {
{ let Some(DecorationValue::Literal(binding)) =
let binding = ast.get_decoration(resource.id, Decoration::Binding)?; ast.decoration(resource.id, Decoration::Binding)?
let location = ResourceBindingLocation { 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, stage,
desc_set: ast.get_decoration(resource.id, Decoration::DescriptorSet)?, ResourceBinding::Qualified {
set: desc_set,
binding, binding,
}; },
&overridden,
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);
} }
Ok(()) Ok(())
} }
set_bindings( set_bindings(&mut self.vertex, spirv::ExecutionModel::Vertex)?;
&self.vertex,
ExecutionModel::Vertex,
&mut vert_options.resource_binding_overrides,
)?;
set_bindings( set_bindings(&mut self.fragment, spirv::ExecutionModel::Fragment)?;
&self.fragment,
ExecutionModel::Fragment,
&mut frag_options.resource_binding_overrides,
)?;
self.vertex.set_compiler_options(&vert_options)?; let vertex_compiled = self.vertex.compile(&options)?;
self.fragment.set_compiler_options(&frag_options)?; let fragment_compiled = self.fragment.compile(&options)?;
Ok(ShaderCompilerOutput { Ok(ShaderCompilerOutput {
vertex: self.vertex.compile()?, vertex: vertex_compiled.to_string(),
fragment: self.fragment.compile()?, fragment: fragment_compiled.to_string(),
context: CrossMslContext { context: CrossMslContext {
artifact: CompiledProgram { artifact: CompiledProgram {
vertex: CompiledAst(self.vertex), vertex: vertex_compiled,
fragment: CompiledAst(self.fragment), fragment: fragment_compiled,
}, },
}, },
}) })
@ -106,15 +108,13 @@ mod test {
use crate::back::targets::{MSL, WGSL}; use crate::back::targets::{MSL, WGSL};
use crate::back::{CompileShader, FromCompilation}; use crate::back::{CompileShader, FromCompilation};
use crate::reflect::cross::SpirvCross; use crate::reflect::cross::SpirvCross;
use crate::reflect::naga::{Naga, NagaLoweringOptions};
use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics}; use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics};
use crate::reflect::ReflectShader; use crate::reflect::ReflectShader;
use bitflags::Flags; use bitflags::Flags;
use librashader_common::map::{FastHashMap, ShortString}; use librashader_common::map::{FastHashMap, ShortString};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use rustc_hash::FxHashMap;
use spirv_cross::msl; use spirv_cross2::compile::msl::MslVersion;
use std::io::Write;
#[test] #[test]
pub fn test_into() { pub fn test_into() {
@ -148,7 +148,7 @@ mod test {
) )
.expect(""); .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); 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 { let &Some(Binding::Location { location, .. }) = &frag_output.binding else {
return Err(ShaderReflectError::VertexSemanticError( return Err(ShaderReflectError::FragmentSemanticError(
SemanticsErrorKind::MissingBinding, SemanticsErrorKind::MissingBinding,
)); ));
}; };
@ -845,10 +845,7 @@ impl NagaReflect {
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
meta: &mut BindingMeta, meta: &mut BindingMeta,
) -> Result<(), ShaderReflectError> { ) -> Result<(), ShaderReflectError> {
let Some(semantic) = semantics let Some(semantic) = semantics.texture_semantics.texture_semantic(texture.name) else {
.texture_semantics
.texture_semantic(texture.name)
else {
return Err( return Err(
SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics( SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics(
texture.name.to_string(), texture.name.to_string(),

View file

@ -8,19 +8,9 @@ use naga::back::msl::{
}; };
use naga::valid::{Capabilities, ValidationFlags}; use naga::valid::{Capabilities, ValidationFlags};
use naga::{Module, TypeInner}; use naga::{Module, TypeInner};
use spirv_cross::msl::Version;
fn msl_version_to_naga_msl(version: MslVersion) -> (u8, u8) { fn msl_version_to_naga_msl(version: MslVersion) -> (u8, u8) {
match version { (version.major as u8, version.minor as u8)
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),
}
} }
impl CompileShader<MSL> for NagaReflect { impl CompileShader<MSL> for NagaReflect {
@ -33,7 +23,7 @@ impl CompileShader<MSL> for NagaReflect {
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> { ) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
// https://github.com/libretro/RetroArch/blob/434e94c782af2e4d4277a24b7ed8e5fc54870088/gfx/drivers_shader/slang_process.cpp#L524 // 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 { let mut vert_options = Options {
lang_version, lang_version,

View file

@ -550,7 +550,7 @@ impl FilterChainD3D12 {
} else { } else {
let hlsl_reflection = hlsl.reflect(index, semantics)?; let hlsl_reflection = hlsl.reflect(index, semantics)?;
let hlsl = hlsl.compile(Some( 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( let graphics_pipeline = D3D12GraphicsPipeline::new_from_hlsl(

View file

@ -96,7 +96,7 @@ impl FilterChainD3D9 {
) -> error::Result<Vec<FilterPass>> { ) -> error::Result<Vec<FilterPass>> {
let builder_fn = |(index, (config, source, mut reflect)): (usize, ShaderPassMeta)| { let builder_fn = |(index, (config, source, mut reflect)): (usize, ShaderPassMeta)| {
let mut reflection = reflect.reflect(index, semantics)?; 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); // 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-runtime = { path = "../librashader-runtime" , version = "0.3.3" }
librashader-cache = { path = "../librashader-cache", 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" gl = "0.14.0"
bytemuck = { version = "1.12.3", features = ["derive"] } bytemuck = { version = "1.12.3", features = ["derive"] }
thiserror = "1.0.37" thiserror = "1.0.37"

View file

@ -13,7 +13,7 @@ pub enum FilterChainError {
#[error("fbo initialization error")] #[error("fbo initialization error")]
FramebufferInit(GLenum), FramebufferInit(GLenum),
#[error("SPIRV reflection error")] #[error("SPIRV reflection error")]
SpirvCrossReflectError(#[from] spirv_cross::ErrorCode), SpirvCrossReflectError(#[from] spirv_cross2::SpirvCrossError),
#[error("shader preset parse error")] #[error("shader preset parse error")]
ShaderPresetError(#[from] ParsePresetError), ShaderPresetError(#[from] ParsePresetError),
#[error("shader preprocess error")] #[error("shader preprocess error")]

View file

@ -5,7 +5,8 @@ use crate::util;
use gl::types::{GLint, GLuint}; use gl::types::{GLint, GLuint};
use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::glsl::CrossGlslContext;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
use spirv_cross::spirv::Decoration; use spirv_cross2::reflect::ResourceType;
use spirv_cross2::spirv::Decoration;
pub struct Gl3CompileProgram; pub struct Gl3CompileProgram;
@ -14,7 +15,7 @@ impl CompileProgram for Gl3CompileProgram {
glsl: ShaderCompilerOutput<String, CrossGlslContext>, glsl: ShaderCompilerOutput<String, CrossGlslContext>,
_cache: bool, _cache: bool,
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> { ) -> 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 (program, ubo_location) = unsafe {
let vertex = util::gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str())?; 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, vertex);
gl::AttachShader(program, fragment); gl::AttachShader(program, fragment);
for res in vertex_resources.stage_inputs { for res in vertex_resources.resources_for_type(ResourceType::StageInput)? {
let loc = glsl let Some(loc) = glsl
.context .context
.artifact .artifact
.vertex .vertex
.get_decoration(res.id, Decoration::Location)?; .decoration(res.id, Decoration::Location)?
let mut name = res.name; .and_then(|d| d.as_literal())
else {
continue;
};
let mut name = res.name.to_string();
name.push('\0'); name.push('\0');
gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) 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_cache::Cacheable;
use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::glsl::CrossGlslContext;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
use spirv_cross::spirv::Decoration; use spirv_cross2::reflect::ResourceType;
use spirv_cross2::spirv::Decoration;
pub struct Gl4CompileProgram; pub struct Gl4CompileProgram;
@ -45,7 +46,7 @@ impl CompileProgram for Gl4CompileProgram {
glsl: ShaderCompilerOutput<String, CrossGlslContext>, glsl: ShaderCompilerOutput<String, CrossGlslContext>,
cache: bool, cache: bool,
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> { ) -> 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( let program = librashader_cache::cache_shader_object(
"opengl4", "opengl4",
@ -58,13 +59,18 @@ impl CompileProgram for Gl4CompileProgram {
gl::AttachShader(program, vertex); gl::AttachShader(program, vertex);
gl::AttachShader(program, fragment); gl::AttachShader(program, fragment);
for res in &vertex_resources.stage_inputs { for res in vertex_resources.resources_for_type(ResourceType::StageInput)? {
let loc = glsl let Some(loc) = glsl
.context .context
.artifact .artifact
.vertex .vertex
.get_decoration(res.id, Decoration::Location)?; .decoration(res.id, Decoration::Location)?
let mut name = res.name.clone(); .and_then(|d| d.as_literal())
else {
continue;
};
let mut name = res.name.to_string();
name.push('\0'); name.push('\0');
gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) 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 { match maj_ver {
3 => match min_ver { 3 => match min_ver {
3 => GlslVersion::V3_30, 3 => GlslVersion::Glsl330,
2 => GlslVersion::V1_50, 2 => GlslVersion::Glsl150,
1 => GlslVersion::V1_40, 1 => GlslVersion::Glsl140,
0 => GlslVersion::V1_30, 0 => GlslVersion::Glsl130,
_ => GlslVersion::V1_50, _ => GlslVersion::Glsl150,
}, },
4 => match min_ver { 4 => match min_ver {
6 => GlslVersion::V4_60, 6 => GlslVersion::Glsl460,
5 => GlslVersion::V4_50, 5 => GlslVersion::Glsl450,
4 => GlslVersion::V4_40, 4 => GlslVersion::Glsl440,
3 => GlslVersion::V4_30, 3 => GlslVersion::Glsl430,
2 => GlslVersion::V4_20, 2 => GlslVersion::Glsl420,
1 => GlslVersion::V4_10, 1 => GlslVersion::Glsl410,
0 => GlslVersion::V4_00, 0 => GlslVersion::Glsl400,
_ => GlslVersion::V1_50, _ => GlslVersion::Glsl150,
}, },
_ => GlslVersion::V1_50, _ => GlslVersion::Glsl150,
} }
} }
pub fn gl_u16_to_version(version: u16) -> GlslVersion { pub fn gl_u16_to_version(version: u16) -> GlslVersion {
match version { match version {
0 => gl_get_version(), 0 => gl_get_version(),
300 => GlslVersion::V1_30, 300 => GlslVersion::Glsl130,
310 => GlslVersion::V1_40, 310 => GlslVersion::Glsl140,
320 => GlslVersion::V1_50, 320 => GlslVersion::Glsl150,
330 => GlslVersion::V3_30, 330 => GlslVersion::Glsl330,
400 => GlslVersion::V4_00, 400 => GlslVersion::Glsl400,
410 => GlslVersion::V4_10, 410 => GlslVersion::Glsl410,
420 => GlslVersion::V4_20, 420 => GlslVersion::Glsl420,
430 => GlslVersion::V4_30, 430 => GlslVersion::Glsl430,
440 => GlslVersion::V4_40, 440 => GlslVersion::Glsl440,
450 => GlslVersion::V4_50, 450 => GlslVersion::Glsl450,
460 => GlslVersion::V4_60, 460 => GlslVersion::Glsl460,
_ => GlslVersion::V1_50, _ => GlslVersion::Glsl150,
} }
} }

View file

@ -154,7 +154,7 @@ impl FilterChainMetal {
.enumerate() .enumerate()
.map(|(index, (config, source, mut reflect))| { .map(|(index, (config, source, mut reflect))| {
let reflection = reflect.reflect(index, semantics)?; 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 ubo_size = reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize);
let push_size = reflection let push_size = reflection

View file

@ -190,8 +190,6 @@ pub mod reflect {
pub use librashader_reflect::back::msl::CrossMslContext; pub use librashader_reflect::back::msl::CrossMslContext;
pub use librashader_reflect::reflect::cross::CompiledAst;
pub use librashader_reflect::reflect::cross::CompiledProgram; pub use librashader_reflect::reflect::cross::CompiledProgram;
} }