hlsl: implement hlsl reflection
This commit is contained in:
parent
d6f47f83ca
commit
f1280202e5
|
@ -9,6 +9,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/naga/benches" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/naga/benches" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/naga/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/naga/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/naga/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/naga/tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-dx11/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -439,6 +439,18 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "librashader-runtime-dx11"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"librashader",
|
||||||
|
"librashader-preprocess",
|
||||||
|
"librashader-presets",
|
||||||
|
"librashader-reflect",
|
||||||
|
"rustc-hash",
|
||||||
|
"spirv_cross",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.17"
|
||||||
|
|
|
@ -4,5 +4,6 @@ members = [
|
||||||
"librashader-presets",
|
"librashader-presets",
|
||||||
"librashader-preprocess",
|
"librashader-preprocess",
|
||||||
"librashader-reflect",
|
"librashader-reflect",
|
||||||
|
"librashader-runtime-dx11",
|
||||||
"naga"
|
"naga"
|
||||||
]
|
]
|
5
librashader-reflect/src/back/cross.rs
Normal file
5
librashader-reflect/src/back/cross.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use crate::back::ShaderCompiler;
|
||||||
|
use crate::back::targets::GLSL;
|
||||||
|
use crate::error::ShaderCompileError;
|
||||||
|
use crate::reflect::ShaderReflection;
|
||||||
|
|
11
librashader-reflect/src/back/mod.rs
Normal file
11
librashader-reflect/src/back/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
pub mod targets;
|
||||||
|
mod cross;
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
pub use targets::ShaderCompiler;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompiledShader<T> {
|
||||||
|
pub vertex: T,
|
||||||
|
pub fragment: T,
|
||||||
|
}
|
22
librashader-reflect/src/back/targets.rs
Normal file
22
librashader-reflect/src/back/targets.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::back::CompiledShader;
|
||||||
|
use crate::error::ShaderCompileError;
|
||||||
|
use crate::reflect::ShaderReflection;
|
||||||
|
|
||||||
|
pub trait OutputTarget { }
|
||||||
|
|
||||||
|
pub struct GLSL;
|
||||||
|
pub struct HLSL;
|
||||||
|
pub struct SpirV;
|
||||||
|
pub struct MSL;
|
||||||
|
|
||||||
|
impl OutputTarget for GLSL {}
|
||||||
|
impl OutputTarget for HLSL {}
|
||||||
|
impl OutputTarget for SpirV {}
|
||||||
|
impl OutputTarget for MSL {}
|
||||||
|
|
||||||
|
pub trait ShaderCompiler<T: OutputTarget> {
|
||||||
|
type Output;
|
||||||
|
type Options;
|
||||||
|
|
||||||
|
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output>, ShaderCompileError>;
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ pub enum ShaderCompileError {
|
||||||
|
|
||||||
#[error("shaderc init")]
|
#[error("shaderc init")]
|
||||||
ShaderCInitError,
|
ShaderCInitError,
|
||||||
|
|
||||||
|
#[error("cross")]
|
||||||
|
SpirvCrossCompileError(#[from] spirv_cross::ErrorCode),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
|
|
||||||
mod error;
|
pub mod error;
|
||||||
mod front;
|
pub mod front;
|
||||||
mod reflect;
|
pub mod reflect;
|
||||||
|
pub mod back;
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
use crate::error::{SemanticsErrorKind, ShaderReflectError};
|
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
|
||||||
use crate::front::shaderc::GlslangCompilation;
|
use crate::front::shaderc::GlslangCompilation;
|
||||||
use crate::reflect::semantics::{
|
use crate::reflect::semantics::{
|
||||||
BindingStage, MemberOffset, PushReflection, SemanticMap, ShaderReflection, TextureImage,
|
BindingStage, MemberOffset, PushReflection, SemanticMap, ShaderReflection, TextureImage,
|
||||||
TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics,
|
TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics,
|
||||||
VariableMeta, VariableSemantics, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
|
VariableMeta, VariableSemantics, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
|
||||||
};
|
};
|
||||||
use crate::reflect::{ReflectMeta, ReflectOptions, ReflectShader, UniformSemantic};
|
use crate::reflect::{ReflectMeta, ReflectSemantics, ReflectShader, UniformSemantic};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use spirv_cross::hlsl::{CompilerOptions, ShaderModel};
|
use spirv_cross::hlsl::{ShaderModel};
|
||||||
use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type};
|
use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type};
|
||||||
use spirv_cross::{hlsl, ErrorCode};
|
use spirv_cross::{hlsl, ErrorCode, glsl};
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use spirv_cross::glsl::Version;
|
||||||
|
use crate::back::{CompiledShader, ShaderCompiler};
|
||||||
|
|
||||||
pub struct CrossReflect<T>
|
pub struct CrossReflect<T>
|
||||||
where
|
where
|
||||||
|
@ -21,6 +23,7 @@ where
|
||||||
fragment: Ast<T>,
|
fragment: Ast<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type HlslReflect = CrossReflect<hlsl::Target>;
|
||||||
impl ValidateTypeSemantics<Type> for VariableSemantics {
|
impl ValidateTypeSemantics<Type> for VariableSemantics {
|
||||||
fn validate_type(&self, ty: &Type) -> Option<TypeInfo> {
|
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 else {
|
let (Type::Float { ref array, vecsize, columns } | Type::Int { ref array, vecsize, columns } | Type::UInt { ref array, vecsize, columns }) = *ty else {
|
||||||
|
@ -89,7 +92,7 @@ impl TryFrom<GlslangCompilation> for CrossReflect<hlsl::Target> {
|
||||||
let mut vertex = Ast::parse(&vertex_module)?;
|
let mut vertex = Ast::parse(&vertex_module)?;
|
||||||
let mut fragment = Ast::parse(&fragment_module)?;
|
let mut fragment = Ast::parse(&fragment_module)?;
|
||||||
|
|
||||||
let mut options = CompilerOptions::default();
|
let mut options = hlsl::CompilerOptions::default();
|
||||||
options.shader_model = ShaderModel::V5_0;
|
options.shader_model = ShaderModel::V5_0;
|
||||||
fragment.set_compiler_options(&options)?;
|
fragment.set_compiler_options(&options)?;
|
||||||
vertex.set_compiler_options(&options)?;
|
vertex.set_compiler_options(&options)?;
|
||||||
|
@ -98,6 +101,25 @@ impl TryFrom<GlslangCompilation> for CrossReflect<hlsl::Target> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<GlslangCompilation> for CrossReflect<glsl::Target> {
|
||||||
|
type Error = ShaderReflectError;
|
||||||
|
|
||||||
|
fn try_from(value: GlslangCompilation) -> Result<Self, Self::Error> {
|
||||||
|
let vertex_module = Module::from_words(value.vertex.as_binary());
|
||||||
|
let fragment_module = Module::from_words(value.fragment.as_binary());
|
||||||
|
|
||||||
|
let mut vertex = Ast::parse(&vertex_module)?;
|
||||||
|
let mut fragment = Ast::parse(&fragment_module)?;
|
||||||
|
|
||||||
|
let mut options = glsl::CompilerOptions::default();
|
||||||
|
options.version = Version::V3_30;
|
||||||
|
fragment.set_compiler_options(&options)?;
|
||||||
|
vertex.set_compiler_options(&options)?;
|
||||||
|
|
||||||
|
Ok(CrossReflect { vertex, fragment })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> CrossReflect<T>
|
impl<T> CrossReflect<T>
|
||||||
where
|
where
|
||||||
T: spirv_cross::spirv::Target,
|
T: spirv_cross::spirv::Target,
|
||||||
|
@ -371,7 +393,8 @@ where
|
||||||
fn reflect_buffer_range_metas(
|
fn reflect_buffer_range_metas(
|
||||||
ast: &Ast<T>,
|
ast: &Ast<T>,
|
||||||
resource: &Resource,
|
resource: &Resource,
|
||||||
options: &ReflectOptions,
|
pass_number: u32,
|
||||||
|
semantics: &ReflectSemantics,
|
||||||
meta: &mut ReflectMeta,
|
meta: &mut ReflectMeta,
|
||||||
offset_type: impl Fn(usize) -> MemberOffset,
|
offset_type: impl Fn(usize) -> MemberOffset,
|
||||||
blame: SemanticErrorBlame,
|
blame: SemanticErrorBlame,
|
||||||
|
@ -392,7 +415,7 @@ where
|
||||||
_ => return Err(blame.error(SemanticsErrorKind::InvalidResourceType)),
|
_ => return Err(blame.error(SemanticsErrorKind::InvalidResourceType)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(parameter) = options.uniform_semantics.get_variable_semantic(&name) {
|
if let Some(parameter) = semantics.uniform_semantics.get_variable_semantic(&name) {
|
||||||
let Some(typeinfo) = parameter.semantics.validate_type(&range_type) else {
|
let Some(typeinfo) = parameter.semantics.validate_type(&range_type) else {
|
||||||
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name)))
|
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name)))
|
||||||
};
|
};
|
||||||
|
@ -453,15 +476,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(texture) = options.uniform_semantics.get_texture_semantic(&name) {
|
} else if let Some(texture) = semantics.uniform_semantics.get_texture_semantic(&name) {
|
||||||
let Some(_typeinfo) = texture.semantics.validate_type(&range_type) else {
|
let Some(_typeinfo) = texture.semantics.validate_type(&range_type) else {
|
||||||
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name)))
|
return Err(blame.error(SemanticsErrorKind::InvalidTypeForSemantic(name)))
|
||||||
};
|
};
|
||||||
|
|
||||||
if let TextureSemantics::PassOutput = texture.semantics {
|
if let TextureSemantics::PassOutput = texture.semantics {
|
||||||
if texture.index >= options.pass_number {
|
if texture.index >= pass_number {
|
||||||
return Err(ShaderReflectError::NonCausalFilterChain {
|
return Err(ShaderReflectError::NonCausalFilterChain {
|
||||||
pass: options.pass_number,
|
pass: pass_number,
|
||||||
target: texture.index,
|
target: texture.index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -486,7 +509,7 @@ where
|
||||||
texture,
|
texture,
|
||||||
TextureSizeMeta {
|
TextureSizeMeta {
|
||||||
offset,
|
offset,
|
||||||
// todo: fix this.
|
// todo: fix this. to allow both
|
||||||
stage_mask: match blame {
|
stage_mask: match blame {
|
||||||
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
||||||
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
||||||
|
@ -502,10 +525,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_ubos(
|
fn reflect_ubos(
|
||||||
&self,
|
&mut self,
|
||||||
vertex_ubo: Option<&Resource>,
|
vertex_ubo: Option<&Resource>,
|
||||||
fragment_ubo: Option<&Resource>,
|
fragment_ubo: Option<&Resource>,
|
||||||
) -> Result<Option<UboReflection>, ShaderReflectError> {
|
) -> Result<Option<UboReflection>, ShaderReflectError> {
|
||||||
|
if let Some(vertex_ubo) = vertex_ubo {
|
||||||
|
self.vertex.set_decoration(vertex_ubo.id, Decoration::Binding, 0)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fragment_ubo) = fragment_ubo {
|
||||||
|
self.fragment.set_decoration(fragment_ubo.id, Decoration::Binding, 0)?;
|
||||||
|
}
|
||||||
|
|
||||||
match (vertex_ubo, fragment_ubo) {
|
match (vertex_ubo, fragment_ubo) {
|
||||||
(None, None) => Ok(None),
|
(None, None) => Ok(None),
|
||||||
(Some(vertex_ubo), Some(fragment_ubo)) => {
|
(Some(vertex_ubo), Some(fragment_ubo)) => {
|
||||||
|
@ -551,18 +582,19 @@ where
|
||||||
fn reflect_texture_metas(
|
fn reflect_texture_metas(
|
||||||
&self,
|
&self,
|
||||||
texture: TextureData,
|
texture: TextureData,
|
||||||
options: &ReflectOptions,
|
pass_number: u32,
|
||||||
|
semantics: &ReflectSemantics,
|
||||||
meta: &mut ReflectMeta,
|
meta: &mut ReflectMeta,
|
||||||
) -> Result<(), ShaderReflectError> {
|
) -> Result<(), ShaderReflectError> {
|
||||||
let Some(semantic) = options.non_uniform_semantics.get_texture_semantic(texture.name) else {
|
let Some(semantic) = semantics.non_uniform_semantics.get_texture_semantic(texture.name) else {
|
||||||
return Err(SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics(texture.name.to_string())))
|
return Err(SemanticErrorBlame::Fragment.error(SemanticsErrorKind::UnknownSemantics(texture.name.to_string())))
|
||||||
};
|
};
|
||||||
|
|
||||||
if semantic.semantics == TextureSemantics::PassOutput
|
if semantic.semantics == TextureSemantics::PassOutput
|
||||||
&& semantic.index >= options.pass_number
|
&& semantic.index >= pass_number
|
||||||
{
|
{
|
||||||
return Err(ShaderReflectError::NonCausalFilterChain {
|
return Err(ShaderReflectError::NonCausalFilterChain {
|
||||||
pass: options.pass_number,
|
pass: pass_number,
|
||||||
target: semantic.index,
|
target: semantic.index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -605,10 +637,19 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_push_constant_buffer(
|
fn reflect_push_constant_buffer(
|
||||||
&self,
|
&mut self,
|
||||||
vertex_pcb: Option<&Resource>,
|
vertex_pcb: Option<&Resource>,
|
||||||
fragment_pcb: Option<&Resource>,
|
fragment_pcb: Option<&Resource>,
|
||||||
) -> Result<Option<PushReflection>, ShaderReflectError> {
|
) -> Result<Option<PushReflection>, ShaderReflectError> {
|
||||||
|
if let Some(vertex_pcb) = vertex_pcb {
|
||||||
|
self.vertex.set_decoration(vertex_pcb.id, Decoration::Binding, 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fragment_pcb) = fragment_pcb {
|
||||||
|
self.fragment.set_decoration(fragment_pcb.id, Decoration::Binding, 1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
match (vertex_pcb, fragment_pcb) {
|
match (vertex_pcb, fragment_pcb) {
|
||||||
(None, None) => Ok(None),
|
(None, None) => Ok(None),
|
||||||
(Some(vertex_push), Some(fragment_push)) => {
|
(Some(vertex_push), Some(fragment_push)) => {
|
||||||
|
@ -656,7 +697,7 @@ where
|
||||||
Ast<T>: spirv_cross::spirv::Compile<T>,
|
Ast<T>: spirv_cross::spirv::Compile<T>,
|
||||||
Ast<T>: spirv_cross::spirv::Parse<T>,
|
Ast<T>: spirv_cross::spirv::Parse<T>,
|
||||||
{
|
{
|
||||||
fn reflect(&self, options: &ReflectOptions) -> Result<ShaderReflection, ShaderReflectError> {
|
fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError> {
|
||||||
let vertex_res = self.vertex.get_shader_resources()?;
|
let vertex_res = self.vertex.get_shader_resources()?;
|
||||||
let fragment_res = self.fragment.get_shader_resources()?;
|
let fragment_res = self.fragment.get_shader_resources()?;
|
||||||
self.validate(&vertex_res, &fragment_res)?;
|
self.validate(&vertex_res, &fragment_res)?;
|
||||||
|
@ -677,7 +718,8 @@ where
|
||||||
Self::reflect_buffer_range_metas(
|
Self::reflect_buffer_range_metas(
|
||||||
&self.vertex,
|
&self.vertex,
|
||||||
ubo,
|
ubo,
|
||||||
options,
|
pass_number,
|
||||||
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::Ubo,
|
MemberOffset::Ubo,
|
||||||
SemanticErrorBlame::Vertex,
|
SemanticErrorBlame::Vertex,
|
||||||
|
@ -688,7 +730,8 @@ where
|
||||||
Self::reflect_buffer_range_metas(
|
Self::reflect_buffer_range_metas(
|
||||||
&self.fragment,
|
&self.fragment,
|
||||||
ubo,
|
ubo,
|
||||||
options,
|
pass_number,
|
||||||
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::Ubo,
|
MemberOffset::Ubo,
|
||||||
SemanticErrorBlame::Fragment,
|
SemanticErrorBlame::Fragment,
|
||||||
|
@ -699,7 +742,8 @@ where
|
||||||
Self::reflect_buffer_range_metas(
|
Self::reflect_buffer_range_metas(
|
||||||
&self.vertex,
|
&self.vertex,
|
||||||
push,
|
push,
|
||||||
options,
|
pass_number,
|
||||||
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::PushConstant,
|
MemberOffset::PushConstant,
|
||||||
SemanticErrorBlame::Vertex,
|
SemanticErrorBlame::Vertex,
|
||||||
|
@ -710,14 +754,14 @@ where
|
||||||
Self::reflect_buffer_range_metas(
|
Self::reflect_buffer_range_metas(
|
||||||
&self.fragment,
|
&self.fragment,
|
||||||
push,
|
push,
|
||||||
options,
|
pass_number,
|
||||||
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::PushConstant,
|
MemberOffset::PushConstant,
|
||||||
SemanticErrorBlame::Fragment,
|
SemanticErrorBlame::Fragment,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: slang_reflection: 556
|
|
||||||
let mut ubo_bindings = 0u16;
|
let mut ubo_bindings = 0u16;
|
||||||
if vertex_ubo.is_some() || fragment_ubo.is_some() {
|
if vertex_ubo.is_some() || fragment_ubo.is_some() {
|
||||||
ubo_bindings = 1 << ubo.as_ref().expect("UBOs should be present").binding;
|
ubo_bindings = 1 << ubo.as_ref().expect("UBOs should be present").binding;
|
||||||
|
@ -730,11 +774,9 @@ where
|
||||||
}
|
}
|
||||||
ubo_bindings |= 1 << texture_data.binding;
|
ubo_bindings |= 1 << texture_data.binding;
|
||||||
|
|
||||||
self.reflect_texture_metas(texture_data, options, &mut meta)?;
|
self.reflect_texture_metas(texture_data, pass_number, semantics, &mut meta)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// slang-reflection:611
|
|
||||||
|
|
||||||
Ok(ShaderReflection {
|
Ok(ShaderReflection {
|
||||||
ubo,
|
ubo,
|
||||||
push_constant,
|
push_constant,
|
||||||
|
@ -743,28 +785,76 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShaderCompiler<crate::back::targets::GLSL> for CrossReflect<glsl::Target> {
|
||||||
|
type Output = String;
|
||||||
|
type Options = glsl::CompilerOptions;
|
||||||
|
|
||||||
|
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output>, ShaderCompileError> {
|
||||||
|
self.vertex.set_compiler_options(options)?;
|
||||||
|
self.fragment.set_compiler_options(options)?;
|
||||||
|
|
||||||
|
Ok(CompiledShader {
|
||||||
|
vertex: self.vertex.compile()?,
|
||||||
|
fragment: self.fragment.compile()?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HlslOptions = hlsl::CompilerOptions;
|
||||||
|
|
||||||
|
impl ShaderCompiler<crate::back::targets::HLSL> for CrossReflect<hlsl::Target> {
|
||||||
|
type Output = String;
|
||||||
|
type Options = hlsl::CompilerOptions;
|
||||||
|
|
||||||
|
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output>, ShaderCompileError> {
|
||||||
|
self.vertex.set_compiler_options(options)?;
|
||||||
|
self.fragment.set_compiler_options(options)?;
|
||||||
|
|
||||||
|
Ok(CompiledShader {
|
||||||
|
vertex: self.vertex.compile()?,
|
||||||
|
fragment: self.fragment.compile()?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use crate::reflect::cross::CrossReflect;
|
use crate::reflect::cross::CrossReflect;
|
||||||
use crate::reflect::{ReflectOptions, ReflectShader};
|
use crate::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
|
||||||
|
|
||||||
use spirv_cross::{hlsl};
|
use spirv_cross::{glsl, hlsl};
|
||||||
|
use spirv_cross::glsl::{CompilerOptions, Version};
|
||||||
|
use crate::back::ShaderCompiler;
|
||||||
|
use crate::reflect::semantics::{SemanticMap, VariableSemantics};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_into() {
|
pub fn test_into() {
|
||||||
let result = librashader_preprocess::load_shader_source("../test/basic.slang").unwrap();
|
let result = librashader_preprocess::load_shader_source("../test/basic.slang").unwrap();
|
||||||
|
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
||||||
|
|
||||||
|
for (index, param) in result.parameters.iter().enumerate() {
|
||||||
|
uniform_semantics.insert(param.id.clone(), UniformSemantic::Variable(SemanticMap {
|
||||||
|
semantics: VariableSemantics::FloatParameter,
|
||||||
|
index: index as u32
|
||||||
|
}));
|
||||||
|
}
|
||||||
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
||||||
let mut reflect = CrossReflect::<hlsl::Target>::try_from(spirv).unwrap();
|
let mut reflect = CrossReflect::<glsl::Target>::try_from(spirv).unwrap();
|
||||||
let huh = reflect
|
let shader_reflection = reflect
|
||||||
.reflect(&ReflectOptions {
|
.reflect(0, &ReflectSemantics {
|
||||||
pass_number: 0,
|
uniform_semantics,
|
||||||
uniform_semantics: Default::default(),
|
|
||||||
non_uniform_semantics: Default::default(),
|
non_uniform_semantics: Default::default(),
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
eprintln!("{huh:#?}");
|
let mut opts = CompilerOptions::default();
|
||||||
eprintln!("{:#}", reflect.fragment.compile().unwrap())
|
opts.version = Version::V4_60;
|
||||||
|
opts.enable_420_pack_extension = false;
|
||||||
|
let compiled = reflect.compile(&opts, &shader_reflection)
|
||||||
|
.unwrap();
|
||||||
|
// eprintln!("{shader_reflection:#?}");
|
||||||
|
eprintln!("{:#}", compiled.fragment)
|
||||||
// let mut loader = rspirv::dr::Loader::new();
|
// let mut loader = rspirv::dr::Loader::new();
|
||||||
// rspirv::binary::parse_words(spirv.fragment.as_binary(), &mut loader).unwrap();
|
// rspirv::binary::parse_words(spirv.fragment.as_binary(), &mut loader).unwrap();
|
||||||
// let module = loader.module();
|
// let module = loader.module();
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::error::{ShaderReflectError};
|
use crate::error::{ShaderReflectError};
|
||||||
use crate::reflect::semantics::{
|
use crate::reflect::semantics::{
|
||||||
SemanticMap, ShaderReflection, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta,
|
SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta,
|
||||||
VariableSemantics,
|
VariableSemantics,
|
||||||
};
|
};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
mod cross;
|
pub mod cross;
|
||||||
mod naga;
|
mod naga;
|
||||||
mod rspirv;
|
mod rspirv;
|
||||||
pub mod semantics;
|
pub mod semantics;
|
||||||
|
|
||||||
pub trait ReflectShader {
|
pub trait ReflectShader {
|
||||||
fn reflect(&self, options: &ReflectOptions) -> Result<ShaderReflection, ShaderReflectError>;
|
fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -21,8 +21,7 @@ pub enum UniformSemantic {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReflectOptions {
|
pub struct ReflectSemantics {
|
||||||
pub pass_number: u32,
|
|
||||||
pub uniform_semantics: FxHashMap<String, UniformSemantic>,
|
pub uniform_semantics: FxHashMap<String, UniformSemantic>,
|
||||||
pub non_uniform_semantics: FxHashMap<String, SemanticMap<TextureSemantics>>,
|
pub non_uniform_semantics: FxHashMap<String, SemanticMap<TextureSemantics>>,
|
||||||
}
|
}
|
||||||
|
@ -35,47 +34,4 @@ pub struct ReflectMeta {
|
||||||
pub texture_size_meta: FxHashMap<SemanticMap<TextureSemantics>, TextureSizeMeta>,
|
pub texture_size_meta: FxHashMap<SemanticMap<TextureSemantics>, TextureSizeMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builtin_uniform_semantics() -> FxHashMap<String, UniformSemantic> {
|
pub use semantics::ShaderReflection;
|
||||||
let mut map = FxHashMap::default();
|
|
||||||
|
|
||||||
map.insert(
|
|
||||||
"MVP".into(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::MVP,
|
|
||||||
index: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
map.insert(
|
|
||||||
"OutputSize".into(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::Output,
|
|
||||||
index: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
map.insert(
|
|
||||||
"FinalViewportSize".into(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::FinalViewport,
|
|
||||||
index: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
map.insert(
|
|
||||||
"FrameCount".into(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::FrameCount,
|
|
||||||
index: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
map.insert(
|
|
||||||
"FrameDirection".into(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::FrameDirection,
|
|
||||||
index: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
map
|
|
||||||
}
|
|
|
@ -81,8 +81,8 @@ pub trait ValidateTypeSemantics<T> {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SemanticMap<T> {
|
pub struct SemanticMap<T> {
|
||||||
pub(crate) semantics: T,
|
pub semantics: T,
|
||||||
pub(crate) index: u32,
|
pub index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
|
14
librashader-runtime-dx11/Cargo.toml
Normal file
14
librashader-runtime-dx11/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "librashader-runtime-dx11"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
"librashader" = { path = "../librashader" }
|
||||||
|
"librashader-presets" = { path = "../librashader-presets" }
|
||||||
|
"librashader-preprocess" = { path = "../librashader-preprocess" }
|
||||||
|
"librashader-reflect" = { path = "../librashader-reflect" }
|
||||||
|
spirv_cross = { version = "0.23.1", features = [ "hlsl" ] }
|
||||||
|
rustc-hash = "1.1.0"
|
137
librashader-runtime-dx11/src/lib.rs
Normal file
137
librashader-runtime-dx11/src/lib.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::path::Path;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use spirv_cross::hlsl::ShaderModel;
|
||||||
|
use librashader::ShaderSource;
|
||||||
|
use librashader_presets::ShaderPassConfig;
|
||||||
|
use librashader_reflect::back::ShaderCompiler;
|
||||||
|
use librashader_reflect::front::shaderc::GlslangCompilation;
|
||||||
|
use librashader_reflect::reflect::cross::{CrossReflect, HlslOptions, HlslReflect};
|
||||||
|
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
|
||||||
|
use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, VariableSemantics};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
|
||||||
|
config: &ShaderPassConfig) {
|
||||||
|
let Some(alias) = &config.alias else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ignore empty aliases
|
||||||
|
if alias.trim().is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = config.id as u32;
|
||||||
|
|
||||||
|
// PassOutput
|
||||||
|
texture_semantics.insert(alias.clone(), SemanticMap {
|
||||||
|
semantics: TextureSemantics::PassOutput,
|
||||||
|
index
|
||||||
|
});
|
||||||
|
uniform_semantics.insert(format!("{alias}Size"), UniformSemantic::Texture(SemanticMap {
|
||||||
|
semantics: TextureSemantics::PassOutput,
|
||||||
|
index
|
||||||
|
}));
|
||||||
|
|
||||||
|
// PassFeedback
|
||||||
|
texture_semantics.insert(format!("{alias}Feedback"), SemanticMap {
|
||||||
|
semantics: TextureSemantics::PassFeedback,
|
||||||
|
index
|
||||||
|
});
|
||||||
|
uniform_semantics.insert(format!("{alias}FeedbackSize"), UniformSemantic::Texture(SemanticMap {
|
||||||
|
semantics: TextureSemantics::PassFeedback,
|
||||||
|
index
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
|
||||||
|
let preset = librashader_presets::ShaderPreset::try_parse(path)?;
|
||||||
|
let mut passes: Vec<(&ShaderPassConfig, ShaderSource, HlslReflect)> = preset.shaders.iter()
|
||||||
|
.map(|shader| {
|
||||||
|
let source = librashader_preprocess::load_shader_source(&shader.name)
|
||||||
|
.unwrap();
|
||||||
|
let spirv = librashader_reflect::front::shaderc::compile_spirv(&source)
|
||||||
|
.unwrap();
|
||||||
|
let mut reflect = librashader_reflect::reflect::cross::HlslReflect::try_from(spirv).unwrap();
|
||||||
|
(shader, source, reflect)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
// todo: this can probably be extracted out.
|
||||||
|
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
||||||
|
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = Default::default();
|
||||||
|
|
||||||
|
for details in &passes {
|
||||||
|
load_pass_semantics(&mut uniform_semantics, &mut texture_semantics, details.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add float params
|
||||||
|
for (index, parameter) in preset.parameters.iter().enumerate() {
|
||||||
|
uniform_semantics.insert(parameter.name.clone(), UniformSemantic::Variable(SemanticMap {
|
||||||
|
semantics: VariableSemantics::FloatParameter,
|
||||||
|
index: index as u32
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add lut params
|
||||||
|
for (index, texture) in preset.textures.iter().enumerate() {
|
||||||
|
texture_semantics.insert(texture.name.clone(), SemanticMap {
|
||||||
|
semantics: TextureSemantics::User,
|
||||||
|
index: index as u32
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let semantics = ReflectSemantics {
|
||||||
|
uniform_semantics,
|
||||||
|
non_uniform_semantics: texture_semantics
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut reflections = Vec::new();
|
||||||
|
let mut compiled = Vec::new();
|
||||||
|
|
||||||
|
for (index, (_, _, reflect)) in passes.iter_mut().enumerate() {
|
||||||
|
let reflection = reflect.reflect(index as u32, &semantics)
|
||||||
|
.unwrap();
|
||||||
|
let mut options: HlslOptions = Default::default();
|
||||||
|
options.shader_model = ShaderModel::V5_0;
|
||||||
|
|
||||||
|
let hlsl = reflect.compile(&options, &reflection)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
eprintln!("{:#}", hlsl.vertex);
|
||||||
|
|
||||||
|
eprintln!("{:#}", hlsl.fragment);
|
||||||
|
|
||||||
|
compiled.push(hlsl);
|
||||||
|
reflections.push(reflection);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
eprintln!("{:#?}", reflections);
|
||||||
|
|
||||||
|
|
||||||
|
// //todo: add the semantics for other shit (slang_process:68)
|
||||||
|
// eprintln!("{:?}", preset);
|
||||||
|
// eprintln!("{:?}", reflect.reflect(&ReflectOptions {
|
||||||
|
// pass_number: i as u32,
|
||||||
|
// uniform_semantics,
|
||||||
|
// non_uniform_semantics: Default::default(),
|
||||||
|
// }));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_preset() {
|
||||||
|
|
||||||
|
load("../test/basic.slangp")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
BIN
test/agb.png
Normal file
BIN
test/agb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -4,10 +4,12 @@
|
||||||
layout(set = 0, binding = 0, std140) uniform UBO
|
layout(set = 0, binding = 0, std140) uniform UBO
|
||||||
{
|
{
|
||||||
mat4 MVP;
|
mat4 MVP;
|
||||||
vec4 SourceSize; // Not used here, but doesn't hurt
|
|
||||||
float ColorMod;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push {
|
||||||
|
float ColorMod;
|
||||||
|
} params;
|
||||||
|
|
||||||
#pragma name StockShader
|
#pragma name StockShader
|
||||||
#pragma format R8G8B8A8_UNORM
|
#pragma format R8G8B8A8_UNORM
|
||||||
#pragma parameter ColorMod "Color intensity" 1.0 0.1 2.0 0.1
|
#pragma parameter ColorMod "Color intensity" 1.0 0.1 2.0 0.1
|
||||||
|
@ -26,10 +28,7 @@ void main()
|
||||||
layout(location = 0) in vec2 vTexCoord;
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
layout(binding = 1) uniform sampler2D Source;
|
layout(binding = 1) uniform sampler2D Source;
|
||||||
// layout(binding = 1) uniform texture2D Source;
|
|
||||||
// layout(binding = 2) uniform sampler _Source_sampler;
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// FragColor = texture(sampler2D(Source, _Source_sampler), vTexCoord) * ColorMod;
|
FragColor = texture(Source, vTexCoord) * params.ColorMod;
|
||||||
FragColor = texture(Source, vTexCoord) * SourceSize[0];
|
|
||||||
}
|
}
|
10
test/basic.slangp
Normal file
10
test/basic.slangp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
shaders = "1"
|
||||||
|
shader0 = "basic.slang"
|
||||||
|
wrap_mode0 = "clamp_to_border"
|
||||||
|
mipmap_input0 = "false"
|
||||||
|
alias0 = ""
|
||||||
|
float_framebuffer0 = "false"
|
||||||
|
srgb_framebuffer0 = "false"
|
||||||
|
ColorMod = "1.700000"
|
||||||
|
textures = "BORDER;"
|
||||||
|
BORDER = "agb.png"
|
Loading…
Reference in a new issue