reflect: partially implement reflection
This commit is contained in:
parent
0f91b9a49e
commit
36a885e55a
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -41,6 +41,12 @@ version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
|
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.73"
|
version = "1.0.73"
|
||||||
|
@ -71,6 +77,15 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
@ -140,6 +155,7 @@ dependencies = [
|
||||||
"librashader",
|
"librashader",
|
||||||
"librashader-preprocess",
|
"librashader-preprocess",
|
||||||
"naga",
|
"naga",
|
||||||
|
"rspirv",
|
||||||
"shaderc",
|
"shaderc",
|
||||||
"spirv_cross",
|
"spirv_cross",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
@ -266,6 +282,17 @@ dependencies = [
|
||||||
"xmlparser",
|
"xmlparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rspirv"
|
||||||
|
version = "0.11.0+1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1503993b59ca9ae4127365c3293517576d7ce56be9f3d8abb1625c85ddc583ba"
|
||||||
|
dependencies = [
|
||||||
|
"fxhash",
|
||||||
|
"num-traits",
|
||||||
|
"spirv",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -14,3 +14,4 @@ thiserror = "1.0.37"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
librashader-preprocess = { path = "../librashader-preprocess", default-features = false }
|
librashader-preprocess = { path = "../librashader-preprocess", default-features = false }
|
||||||
|
rspirv = "0.11.0+1.5.4"
|
||||||
|
|
|
@ -12,12 +12,32 @@ pub enum ShaderCompileError {
|
||||||
ShaderCInitError,
|
ShaderCInitError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SemanticsErrorKind {
|
||||||
|
InvalidUniformBufferSize(usize),
|
||||||
|
InvalidPushBufferSize(usize),
|
||||||
|
InvalidLocation(u32),
|
||||||
|
InvalidDescriptorSet(u32),
|
||||||
|
InvalidInputCount(usize),
|
||||||
|
InvalidOutputCount(usize),
|
||||||
|
InvalidBinding(u32),
|
||||||
|
InvalidResourceType,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ShaderReflectError {
|
pub enum ShaderReflectError {
|
||||||
#[error("shader")]
|
#[error("shader")]
|
||||||
NagaCompileError(#[from] naga::front::spv::Error),
|
NagaCompileError(#[from] naga::front::spv::Error),
|
||||||
#[error("spirv")]
|
#[error("spirv")]
|
||||||
SpirvCrossError(#[from] spirv_cross::ErrorCode),
|
SpirvCrossError(#[from] spirv_cross::ErrorCode),
|
||||||
|
#[error("error when verifying vertex semantics")]
|
||||||
|
VertexSemanticError(SemanticsErrorKind),
|
||||||
|
#[error("error when verifying texture semantics")]
|
||||||
|
FragmentSemanticError(SemanticsErrorKind),
|
||||||
|
#[error("vertx and fragment shader must have same binding")]
|
||||||
|
MismatchedUniformBuffer { vertex: Option<u32>, fragment: Option<u32> },
|
||||||
|
#[error("binding exceeded max")]
|
||||||
|
InvalidBinding(u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<naga::front::glsl::Error>> for ShaderCompileError {
|
impl From<Vec<naga::front::glsl::Error>> for ShaderCompileError {
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn get_shaderc_options() -> Result<CompileOptions<'static>, ShaderCompileError>
|
||||||
|
|
||||||
pub fn compile_spirv(source: &ShaderSource) -> Result<GlslangCompilation, ShaderCompileError> {
|
pub fn compile_spirv(source: &ShaderSource) -> Result<GlslangCompilation, ShaderCompileError> {
|
||||||
let compiler = shaderc::Compiler::new().ok_or(ShaderCompileError::ShaderCInitError)?;
|
let compiler = shaderc::Compiler::new().ok_or(ShaderCompileError::ShaderCInitError)?;
|
||||||
let name = source.name.as_deref().unwrap_or("shader.glsl");
|
let name = source.name.as_deref().unwrap_or("shader.slang");
|
||||||
let options = get_shaderc_options()?;
|
let options = get_shaderc_options()?;
|
||||||
|
|
||||||
let vertex = compiler.compile_into_spirv(
|
let vertex = compiler.compile_into_spirv(
|
||||||
|
|
205
librashader-reflect/src/reflect/cross.rs
Normal file
205
librashader-reflect/src/reflect/cross.rs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
use crate::error::{ShaderReflectError, SemanticsErrorKind};
|
||||||
|
use crate::front::shaderc::GlslangCompilation;
|
||||||
|
use crate::reflect::semantics::{MAX_BINDING_NUM, MAX_BINDINGS_COUNT, ShaderReflection};
|
||||||
|
use crate::reflect::ReflectShader;
|
||||||
|
use spirv_cross::spirv::{Ast, Decoration, Module, ShaderResources};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use spirv_cross::ErrorCode;
|
||||||
|
|
||||||
|
pub struct CrossReflect<T>
|
||||||
|
where
|
||||||
|
T: spirv_cross::spirv::Target,
|
||||||
|
{
|
||||||
|
vertex: Ast<T>,
|
||||||
|
fragment: Ast<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TryFrom<GlslangCompilation> for CrossReflect<T>
|
||||||
|
where
|
||||||
|
T: spirv_cross::spirv::Target,
|
||||||
|
Ast<T>: spirv_cross::spirv::Compile<T>,
|
||||||
|
Ast<T>: spirv_cross::spirv::Parse<T>,
|
||||||
|
{
|
||||||
|
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 vertex = Ast::parse(&vertex_module)?;
|
||||||
|
let fragment = Ast::parse(&fragment_module)?;
|
||||||
|
|
||||||
|
Ok(CrossReflect { vertex, fragment })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl <T> CrossReflect<T>
|
||||||
|
where
|
||||||
|
T: spirv_cross::spirv::Target,
|
||||||
|
Ast<T>: spirv_cross::spirv::Compile<T>,
|
||||||
|
Ast<T>: spirv_cross::spirv::Parse<T>,
|
||||||
|
{
|
||||||
|
fn validate(&self, vertex_res: &ShaderResources, fragment_res: &ShaderResources) -> Result<(), ShaderReflectError> {
|
||||||
|
if !vertex_res.sampled_images.is_empty()
|
||||||
|
|| !vertex_res.storage_buffers.is_empty()
|
||||||
|
|| !vertex_res.subpass_inputs.is_empty()
|
||||||
|
|| !vertex_res.storage_images.is_empty()
|
||||||
|
|| !vertex_res.atomic_counters.is_empty()
|
||||||
|
{
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidResourceType,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fragment_res.storage_buffers.is_empty()
|
||||||
|
|| !fragment_res.subpass_inputs.is_empty()
|
||||||
|
|| !fragment_res.storage_images.is_empty()
|
||||||
|
|| !fragment_res.atomic_counters.is_empty()
|
||||||
|
{
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidResourceType,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vert_inputs = vertex_res.stage_inputs.len();
|
||||||
|
if vert_inputs != 2 {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidInputCount(vert_inputs),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let frag_outputs = fragment_res.stage_outputs.len();
|
||||||
|
if frag_outputs != 1 {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidOutputCount(frag_outputs),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let fragment_location = self.fragment.get_decoration(fragment_res.stage_outputs[0].id, Decoration::Location)?;
|
||||||
|
if fragment_location != 0 {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidLocation(fragment_location),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut 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 {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidLocation(vert_mask),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if vertex_res.uniform_buffers.len() > 1 {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidUniformBufferSize(vertex_res.uniform_buffers.len()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if vertex_res.push_constant_buffers.len() > 1 {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidUniformBufferSize(vertex_res.push_constant_buffers.len()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if fragment_res.uniform_buffers.len() > 1 {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidUniformBufferSize(fragment_res.uniform_buffers.len()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if fragment_res.push_constant_buffers.len() > 1 {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(
|
||||||
|
SemanticsErrorKind::InvalidUniformBufferSize(fragment_res.push_constant_buffers.len()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>,
|
||||||
|
{
|
||||||
|
fn reflect(&self) -> Result<ShaderReflection, ShaderReflectError> {
|
||||||
|
let vertex_res = self.vertex.get_shader_resources()?;
|
||||||
|
let fragment_res = self.fragment.get_shader_resources()?;
|
||||||
|
self.validate(&vertex_res, &fragment_res)?;
|
||||||
|
|
||||||
|
let vertex_ubo = vertex_res.uniform_buffers.first().map(|f| f.id);
|
||||||
|
let fragment_ubo = fragment_res.uniform_buffers.first().map(|f| f.id);
|
||||||
|
|
||||||
|
let vertex_push = vertex_res.push_constant_buffers.first().map(|f| f.id);
|
||||||
|
let fragment_push = fragment_res.push_constant_buffers.first().map(|f| f.id);
|
||||||
|
|
||||||
|
if let Some(ubo) = vertex_ubo {
|
||||||
|
let desc_set = self.vertex.get_decoration(ubo, Decoration::DescriptorSet)?;
|
||||||
|
if desc_set != 0 {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(SemanticsErrorKind::InvalidDescriptorSet(desc_set)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ubo) = fragment_ubo {
|
||||||
|
let desc_set = self.fragment.get_decoration(ubo, Decoration::DescriptorSet)?;
|
||||||
|
if desc_set != 0 {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(SemanticsErrorKind::InvalidDescriptorSet(desc_set)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vertex_ubo_binding = vertex_ubo.map(|s| self.vertex.get_decoration(s, Decoration::Binding))
|
||||||
|
.map_or(Ok(None), |v| v.map(Some))?;
|
||||||
|
|
||||||
|
let fragment_ubo_binding = vertex_ubo.map(|s| self.fragment.get_decoration(s, Decoration::Binding))
|
||||||
|
.map_or(Ok(None), |v| v.map(Some))?;
|
||||||
|
|
||||||
|
match (vertex_ubo_binding, fragment_ubo_binding) {
|
||||||
|
(Some(vertex), Some(fragment)) => {
|
||||||
|
if vertex != fragment {
|
||||||
|
return Err(ShaderReflectError::MismatchedUniformBuffer {
|
||||||
|
vertex: vertex_ubo_binding,
|
||||||
|
fragment: fragment_ubo_binding
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if vertex >= MAX_BINDINGS_COUNT {
|
||||||
|
return Err(ShaderReflectError::InvalidBinding(vertex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(vertex), None) => {
|
||||||
|
if vertex >= MAX_BINDINGS_COUNT {
|
||||||
|
return Err(ShaderReflectError::VertexSemanticError(SemanticsErrorKind::InvalidBinding(vertex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(None, Some(fragment)) => {
|
||||||
|
if fragment >= MAX_BINDINGS_COUNT {
|
||||||
|
return Err(ShaderReflectError::FragmentSemanticError(SemanticsErrorKind::InvalidBinding(vertex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(None, None) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: slang_reflection:490
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::reflect::cross::CrossReflect;
|
||||||
|
use rspirv::binary::Disassemble;
|
||||||
|
use spirv_cross::{glsl, hlsl};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_into() {
|
||||||
|
let result = librashader_preprocess::load_shader_source("../test/basic.slang").unwrap();
|
||||||
|
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
||||||
|
let mut reflect = CrossReflect::<glsl::Target>::try_from(spirv).unwrap();
|
||||||
|
// let mut loader = rspirv::dr::Loader::new();
|
||||||
|
// rspirv::binary::parse_words(spirv.fragment.as_binary(), &mut loader).unwrap();
|
||||||
|
// let module = loader.module();
|
||||||
|
// println!("{:#}", module.disassemble());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,10 @@
|
||||||
|
use crate::error::ShaderReflectError;
|
||||||
|
use crate::reflect::semantics::ShaderReflection;
|
||||||
|
|
||||||
|
mod cross;
|
||||||
mod naga;
|
mod naga;
|
||||||
mod spirv_cross;
|
pub mod semantics;
|
||||||
|
|
||||||
|
pub trait ReflectShader {
|
||||||
|
fn reflect(&self) -> Result<ShaderReflection, ShaderReflectError>;
|
||||||
|
}
|
||||||
|
|
|
@ -26,8 +26,12 @@ impl TryFrom<GlslangCompilation> for NagaReflect {
|
||||||
|
|
||||||
fn try_from(value: GlslangCompilation) -> Result<Self, Self::Error> {
|
fn try_from(value: GlslangCompilation) -> Result<Self, Self::Error> {
|
||||||
let ops = Options::default();
|
let ops = Options::default();
|
||||||
let vertex = naga::front::spv::parse_u8_slice(value.vertex.as_binary_u8(), &ops)?;
|
let vertex =
|
||||||
let fragment = naga::front::spv::parse_u8_slice(value.fragment.as_binary_u8(), &ops)?;
|
naga::front::spv::Parser::new(value.vertex.as_binary().to_vec().into_iter(), &ops)
|
||||||
|
.parse()?;
|
||||||
|
let fragment =
|
||||||
|
naga::front::spv::Parser::new(value.fragment.as_binary().to_vec().into_iter(), &ops)
|
||||||
|
.parse()?;
|
||||||
Ok(NagaReflect { vertex, fragment })
|
Ok(NagaReflect { vertex, fragment })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,15 +40,11 @@ impl TryFrom<GlslangCompilation> for NagaReflect {
|
||||||
mod test {
|
mod test {
|
||||||
use crate::reflect::naga::NagaReflect;
|
use crate::reflect::naga::NagaReflect;
|
||||||
use naga::front::spv::Options;
|
use naga::front::spv::Options;
|
||||||
|
use rspirv::binary::Disassemble;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_into() {
|
pub fn test_into() {
|
||||||
let result = librashader_preprocess::load_shader_source(
|
let result = librashader_preprocess::load_shader_source("../test/basic.slang").unwrap();
|
||||||
"../test/slang-shaders/blurs/shaders/royale/blur3x3-last-pass.slang",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
||||||
|
|
||||||
println!("{:?}", NagaReflect::try_from(spirv))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
41
librashader-reflect/src/reflect/semantics.rs
Normal file
41
librashader-reflect/src/reflect/semantics.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use crate::error::ShaderReflectError;
|
||||||
|
|
||||||
|
pub const BASE_SEMANTICS_COUNT: usize = 5;
|
||||||
|
pub const MAX_BINDINGS_COUNT: u32 = 16;
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum VariableSemantics {
|
||||||
|
// mat4, MVP
|
||||||
|
MVP = 0,
|
||||||
|
// vec4, viewport size of current pass
|
||||||
|
Output = 1,
|
||||||
|
// vec4, viewport size of final pass
|
||||||
|
FinalViewport = 2,
|
||||||
|
// uint, frame count with modulo
|
||||||
|
FrameCount = 3,
|
||||||
|
// int, frame direction
|
||||||
|
FrameDirection = 4,
|
||||||
|
// float, user defined parameter, array
|
||||||
|
FloatParameter = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum TextureSemantics {
|
||||||
|
Original = 0,
|
||||||
|
Source = 1,
|
||||||
|
OriginalHistory = 2,
|
||||||
|
PassOutput = 3,
|
||||||
|
PassFeedback = 4,
|
||||||
|
User = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BufferReflection {
|
||||||
|
pub binding: Option<u32>,
|
||||||
|
pub size: usize,
|
||||||
|
pub stage_mask: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShaderReflection {
|
||||||
|
pub ubo: Option<BufferReflection>,
|
||||||
|
pub push_constant: Option<BufferReflection>,
|
||||||
|
}
|
|
@ -1,46 +0,0 @@
|
||||||
use crate::error::ShaderReflectError;
|
|
||||||
use crate::front::shaderc::GlslangCompilation;
|
|
||||||
use spirv_cross::spirv::{Ast, Module};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
pub struct SpirvCrossReflect<T>
|
|
||||||
where
|
|
||||||
T: spirv_cross::spirv::Target,
|
|
||||||
{
|
|
||||||
vertex: Ast<T>,
|
|
||||||
fragment: Ast<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TryFrom<GlslangCompilation> for SpirvCrossReflect<T>
|
|
||||||
where
|
|
||||||
T: spirv_cross::spirv::Target,
|
|
||||||
Ast<T>: spirv_cross::spirv::Compile<T>,
|
|
||||||
Ast<T>: spirv_cross::spirv::Parse<T>,
|
|
||||||
{
|
|
||||||
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 vertex = Ast::parse(&vertex_module)?;
|
|
||||||
let fragment = Ast::parse(&fragment_module)?;
|
|
||||||
Ok(SpirvCrossReflect { vertex, fragment })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::reflect::spirv_cross::SpirvCrossReflect;
|
|
||||||
use spirv_cross::glsl;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_into() {
|
|
||||||
let result = librashader_preprocess::load_shader_source(
|
|
||||||
"../test/slang-shaders/blurs/shaders/royale/blur3x3-last-pass.slang",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let spirv = crate::front::shaderc::compile_spirv(&result).unwrap();
|
|
||||||
SpirvCrossReflect::<glsl::Target>::try_from(spirv).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
32
test/basic.slang
Normal file
32
test/basic.slang
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#version 450
|
||||||
|
// 450 or 310 es are recommended
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0, std140) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
vec4 SourceSize; // Not used here, but doesn't hurt
|
||||||
|
float ColorMod;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma name StockShader
|
||||||
|
#pragma format R8G8B8A8_UNORM
|
||||||
|
#pragma parameter ColorMod "Color intensity" 1.0 0.1 2.0 0.1
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(binding = 1) uniform sampler2D Source;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = texture(Source, vTexCoord) * ColorMod;
|
||||||
|
}
|
Loading…
Reference in a new issue