reflect: port to spirv-cross2
This commit is contained in:
parent
820fb69328
commit
c3033cfbbf
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ¶meter.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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue