commit
0755b4f807
@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "shade_runner"
|
||||
version = "0.1.0"
|
||||
authors = ["Tom Gowan <tomrgowan@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
notify = "4"
|
||||
shaderc = "0.3"
|
||||
spirv-reflect = "0.2"
|
||||
vulkano = "0.11"
|
||||
|
||||
[dev-dependencies]
|
||||
vulkano = "0.11"
|
||||
color-backtrace = "0.1"
|
||||
difference = "2"
|
||||
|
||||
[patch.crates-io]
|
||||
vulkano = { git = "https://github.com/mitchmindtree/vulkano", branch = "nannou_patches" }
|
@ -0,0 +1,13 @@
|
||||
use shade_runner as sr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let project_root = std::env::current_dir().expect("failed to get root directory");
|
||||
let mut vert_path = project_root.clone();
|
||||
vert_path.push(PathBuf::from("examples/shaders/vert.glsl"));
|
||||
let mut frag_path = project_root.clone();
|
||||
frag_path.push(PathBuf::from("examples/shaders/frag.glsl"));
|
||||
let shader = sr::load(vert_path, frag_path).expect("Failed to compile");
|
||||
let vulkano_entry = sr::parse(&shader);
|
||||
dbg!(vulkano_entry);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(0.0, 0.5, 1.0, 1.0);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
vec2 p = position;
|
||||
p.x += 0.2;
|
||||
gl_Position = vec4(p, 0.0, 1.0);
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use shaderc::ShaderKind;
|
||||
use std::io::Read;
|
||||
|
||||
pub fn compile<T>(path: T, shader_kind: ShaderKind) -> shaderc::Result<Vec<u32>>
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
{
|
||||
// TODO Probably shouldn't create this every time.
|
||||
let mut compiler = shaderc::Compiler::new().expect("failed to create compiler");
|
||||
let mut f = File::open(&path).expect("failed to open shader src");
|
||||
let mut src = String::new();
|
||||
f.read_to_string(&mut src).expect("failed to read src");
|
||||
let mut options = shaderc::CompileOptions::new().unwrap();
|
||||
options.add_macro_definition("EP", Some("main"));
|
||||
let result = compiler.compile_into_spirv(
|
||||
src.as_str(),
|
||||
shader_kind,
|
||||
path.as_ref().to_str().expect("failed to make path string"),
|
||||
"main",
|
||||
None,
|
||||
)?;
|
||||
let data = result.as_binary();
|
||||
Ok(data.to_owned())
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Compile(shaderc::Error),
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
use crate::vk;
|
||||
use vk::pipeline::shader::*;
|
||||
use vk::descriptor::descriptor::*;
|
||||
use vk::descriptor::pipeline_layout::*;
|
||||
use crate::reflection::LayoutData;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Entry {
|
||||
pub frag_input: FragInput,
|
||||
pub frag_output: FragOutput,
|
||||
pub frag_layout: FragLayout,
|
||||
pub vert_input: VertInput,
|
||||
pub vert_output: VertOutput,
|
||||
pub vert_layout: VertLayout,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FragInput {
|
||||
pub inputs: Vec<ShaderInterfaceDefEntry>,
|
||||
}
|
||||
|
||||
unsafe impl ShaderInterfaceDef for FragInput {
|
||||
type Iter = FragInputIter;
|
||||
|
||||
fn elements(&self) -> FragInputIter {
|
||||
self.inputs.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub type FragInputIter = std::vec::IntoIter<ShaderInterfaceDefEntry>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FragOutput {
|
||||
pub outputs: Vec<ShaderInterfaceDefEntry>,
|
||||
}
|
||||
|
||||
unsafe impl ShaderInterfaceDef for FragOutput {
|
||||
type Iter = FragOutputIter;
|
||||
|
||||
fn elements(&self) -> FragOutputIter {
|
||||
self.outputs.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub type FragOutputIter = std::vec::IntoIter<ShaderInterfaceDefEntry>;
|
||||
|
||||
// Layout same as with vertex shader.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FragLayout {
|
||||
pub stages: ShaderStages,
|
||||
pub layout_data: LayoutData,
|
||||
}
|
||||
unsafe impl PipelineLayoutDesc for FragLayout {
|
||||
fn num_sets(&self) -> usize {
|
||||
self.layout_data.num_sets
|
||||
}
|
||||
fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
|
||||
self.layout_data.num_bindings.get(&set).map(|&i| i)
|
||||
}
|
||||
fn descriptor(&self, _set: usize, _binding: usize) -> Option<DescriptorDesc> {
|
||||
None
|
||||
}
|
||||
fn num_push_constants_ranges(&self) -> usize {
|
||||
0
|
||||
}
|
||||
fn push_constants_range(&self, _num: usize) -> Option<PipelineLayoutDescPcRange> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VertInput {
|
||||
pub inputs: Vec<ShaderInterfaceDefEntry>,
|
||||
}
|
||||
|
||||
unsafe impl ShaderInterfaceDef for VertInput {
|
||||
type Iter = VertInputIter;
|
||||
|
||||
fn elements(&self) -> VertInputIter {
|
||||
self.inputs.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub type VertInputIter = std::vec::IntoIter<ShaderInterfaceDefEntry>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VertOutput {
|
||||
pub outputs: Vec<ShaderInterfaceDefEntry>,
|
||||
}
|
||||
|
||||
unsafe impl ShaderInterfaceDef for VertOutput {
|
||||
type Iter = VertOutputIter;
|
||||
|
||||
fn elements(&self) -> VertOutputIter {
|
||||
self.outputs.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub type VertOutputIter = std::vec::IntoIter<ShaderInterfaceDefEntry>;
|
||||
|
||||
// This structure describes layout of this stage.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct VertLayout(pub ShaderStages);
|
||||
unsafe impl PipelineLayoutDesc for VertLayout {
|
||||
// Number of descriptor sets it takes.
|
||||
fn num_sets(&self) -> usize {
|
||||
0
|
||||
}
|
||||
// Number of entries (bindings) in each set.
|
||||
fn num_bindings_in_set(&self, _set: usize) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
// Descriptor descriptions.
|
||||
fn descriptor(&self, _set: usize, _binding: usize) -> Option<DescriptorDesc> {
|
||||
None
|
||||
}
|
||||
// Number of push constants ranges (think: number of push constants).
|
||||
fn num_push_constants_ranges(&self) -> usize {
|
||||
0
|
||||
}
|
||||
// Each push constant range in memory.
|
||||
fn push_constants_range(&self, _num: usize) -> Option<PipelineLayoutDescPcRange> {
|
||||
None
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
mod compiler;
|
||||
mod error;
|
||||
mod reflection;
|
||||
mod srvk;
|
||||
mod layouts;
|
||||
|
||||
pub use layouts::*;
|
||||
pub use reflection::LayoutData;
|
||||
|
||||
use spirv_reflect as sr;
|
||||
use vulkano as vk;
|
||||
use std::path::Path;
|
||||
use error::Error;
|
||||
use shaderc::ShaderKind;
|
||||
|
||||
pub struct CompiledShaders {
|
||||
pub vertex: Vec<u32>,
|
||||
pub fragment: Vec<u32>,
|
||||
}
|
||||
|
||||
pub fn load<T>(vertex: T, fragment: T) -> Result<CompiledShaders, Error>
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
{
|
||||
let vertex = compiler::compile(vertex, ShaderKind::Vertex).map_err(|e| Error::Compile(e))?;
|
||||
let fragment = compiler::compile(fragment, ShaderKind::Fragment).map_err(|e| Error::Compile(e))?;
|
||||
Ok(CompiledShaders{ vertex, fragment })
|
||||
}
|
||||
|
||||
pub fn parse(code: &CompiledShaders) -> Entry {
|
||||
reflection::create_entry(code)
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
use crate::sr;
|
||||
use crate::srvk::SpirvTy;
|
||||
use std::borrow::Cow;
|
||||
use crate::vk::pipeline::shader::ShaderInterfaceDefEntry;
|
||||
use crate::vk::descriptor::descriptor::ShaderStages;
|
||||
use std::collections::HashMap;
|
||||
use crate::CompiledShaders;
|
||||
use crate::layouts::*;
|
||||
|
||||
pub struct ShaderInterfaces {
|
||||
pub inputs: Vec<ShaderInterfaceDefEntry>,
|
||||
pub outputs: Vec<ShaderInterfaceDefEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct LayoutData {
|
||||
pub num_sets: usize,
|
||||
pub num_bindings: HashMap<usize, usize>,
|
||||
}
|
||||
|
||||
pub fn create_entry(shaders: &CompiledShaders) -> Entry {
|
||||
let vertex_interfaces = create_interfaces(&shaders.vertex);
|
||||
let fragment_interfaces = create_interfaces(&shaders.fragment);
|
||||
let frag_input = FragInput{ inputs: fragment_interfaces.inputs };
|
||||
let frag_output = FragOutput{ outputs: fragment_interfaces.outputs };
|
||||
let frag_layout = FragLayout {
|
||||
stages: ShaderStages {
|
||||
fragment: true,
|
||||
..ShaderStages::none()
|
||||
},
|
||||
layout_data: Default::default(),
|
||||
};
|
||||
let vert_input = VertInput{ inputs: vertex_interfaces.inputs };
|
||||
let vert_output = VertOutput{ outputs: vertex_interfaces.outputs };
|
||||
let vert_layout = VertLayout(ShaderStages {
|
||||
vertex: true,
|
||||
..ShaderStages::none()
|
||||
});
|
||||
Entry {
|
||||
frag_input,
|
||||
frag_output,
|
||||
vert_input,
|
||||
vert_output,
|
||||
frag_layout,
|
||||
vert_layout,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn create_interfaces(data: &[u32]) -> ShaderInterfaces {
|
||||
sr::ShaderModule::load_u32_data(data)
|
||||
.map(|m| {
|
||||
let inputs = m
|
||||
.enumerate_input_variables(None)
|
||||
.map(|inputs| {
|
||||
inputs
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
!i.decoration_flags
|
||||
.contains(sr::types::ReflectDecorationFlags::BUILT_IN)
|
||||
})
|
||||
.map(|i| ShaderInterfaceDefEntry {
|
||||
location: i.location..(i.location + 1),
|
||||
format: SpirvTy::from(i.format).inner(),
|
||||
name: Some(Cow::from(i.name.clone())),
|
||||
})
|
||||
.collect::<Vec<ShaderInterfaceDefEntry>>()
|
||||
})
|
||||
.expect("Failed to pass inputs");
|
||||
let outputs = m
|
||||
.enumerate_output_variables(None)
|
||||
.map(|outputs| {
|
||||
outputs
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
!i.decoration_flags
|
||||
.contains(sr::types::ReflectDecorationFlags::BUILT_IN)
|
||||
})
|
||||
.map(|i| ShaderInterfaceDefEntry {
|
||||
location: i.location..(i.location + 1),
|
||||
format: SpirvTy::from(i.format).inner(),
|
||||
name: Some(Cow::from(i.name.clone())),
|
||||
})
|
||||
.collect::<Vec<ShaderInterfaceDefEntry>>()
|
||||
})
|
||||
.expect("Failed to pass outputs");
|
||||
ShaderInterfaces { inputs, outputs }
|
||||
})
|
||||
.expect("failed to load module")
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
use crate::sr;
|
||||
use crate::vk;
|
||||
use vk::descriptor::descriptor::*;
|
||||
use vk::pipeline::shader::ShaderInterfaceDefEntry;
|
||||
use vk::format::Format;
|
||||
|
||||
pub struct SpirvTy<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
pub struct DescriptorDescInfo {
|
||||
descriptor_type: sr::types::ReflectDescriptorType,
|
||||
image: sr::types::ReflectImageTraits,
|
||||
}
|
||||
|
||||
impl<T> SpirvTy<T> {
|
||||
pub fn inner(self) -> T {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DescriptorDescInfo> for SpirvTy<DescriptorDescTy> {
|
||||
fn from(d: DescriptorDescInfo) -> Self {
|
||||
use sr::types::ReflectDescriptorType as SR;
|
||||
use DescriptorDescTy as VK;
|
||||
let t = match d.descriptor_type {
|
||||
SR::Undefined => unreachable!(),
|
||||
SR::Sampler => VK::Sampler,
|
||||
SR::CombinedImageSampler => VK::CombinedImageSampler(SpirvTy::from(d.image).inner()),
|
||||
SR::SampledImage => unreachable!(),
|
||||
SR::StorageImage => unreachable!(),
|
||||
SR::UniformTexelBuffer => unreachable!(),
|
||||
SR::StorageTexelBuffer => unreachable!(),
|
||||
SR::UniformBuffer => unreachable!(),
|
||||
SR::StorageBuffer => unreachable!(),
|
||||
SR::UniformBufferDynamic => unreachable!(),
|
||||
SR::StorageBufferDynamic => unreachable!(),
|
||||
SR::InputAttachment => unreachable!(),
|
||||
SR::AccelerationStructureNV => unreachable!(),
|
||||
};
|
||||
SpirvTy {
|
||||
inner: t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sr::types::ReflectImageTraits> for SpirvTy<DescriptorImageDesc> {
|
||||
fn from(d: sr::types::ReflectImageTraits) -> Self {
|
||||
let conv_array_layers = |a, d|{
|
||||
if a != 0 {
|
||||
DescriptorImageDescArray::Arrayed{max_layers: Some(d)}
|
||||
} else {
|
||||
DescriptorImageDescArray::NonArrayed
|
||||
}
|
||||
};
|
||||
let t = DescriptorImageDesc {
|
||||
sampled: d.sampled != 0,
|
||||
dimensions: SpirvTy::from(d.dim).inner(),
|
||||
format: Some(SpirvTy::from(d.image_format).inner()),
|
||||
multisampled: d.ms != 0,
|
||||
array_layers: conv_array_layers(d.arrayed, d.depth),
|
||||
};
|
||||
SpirvTy{inner: t}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sr::types::variable::ReflectDimension> for SpirvTy<DescriptorImageDescDimensions> {
|
||||
fn from(d: sr::types::variable::ReflectDimension) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sr::types::image::ReflectImageFormat> for SpirvTy<Format> {
|
||||
fn from(d: sr::types::image::ReflectImageFormat) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sr::types::ReflectFormat> for SpirvTy<Format> {
|
||||
fn from(f: sr::types::ReflectFormat) -> Self {
|
||||
use sr::types::ReflectFormat::*;
|
||||
use Format::*;
|
||||
let t = match f {
|
||||
Undefined => unreachable!(),
|
||||
R32_UINT => R32Uint,
|
||||
R32_SINT => R32Sint,
|
||||
R32_SFLOAT => R32Sfloat,
|
||||
R32G32_UINT => R32G32Uint,
|
||||
R32G32_SINT => R32G32Sint,
|
||||
R32G32_SFLOAT => R32G32Sfloat,
|
||||
R32G32B32_UINT => R32G32B32Uint,
|
||||
R32G32B32_SINT => R32G32B32Sint,
|
||||
R32G32B32_SFLOAT => R32G32B32Sfloat,
|
||||
R32G32B32A32_UINT => R32G32B32A32Uint,
|
||||
R32G32B32A32_SINT => R32G32B32A32Sint,
|
||||
R32G32B32A32_SFLOAT => R32G32B32A32Sfloat,
|
||||
};
|
||||
SpirvTy { inner: t }
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(0.0, 0.5, 1.0, 1.0);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec4 cool;
|
||||
layout(location = 1) in vec2 yep;
|
||||
layout(location = 2) in float monkey;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
vec4 t = cool;
|
||||
t.yw += yep;
|
||||
t.x -= monkey;
|
||||
f_color = t;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
vec2 p = position;
|
||||
p.x += 0.2;
|
||||
gl_Position = vec4(p, 0.0, 1.0);
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) out vec4 cool;
|
||||
layout(location = 1) out vec2 yep;
|
||||
layout(location = 2) out float monkey;
|
||||
|
||||
void main() {
|
||||
cool = vec4(0.0, 0.5, 1.0, 1.0);
|
||||
yep = position;
|
||||
monkey = 0.9;
|
||||
gl_Position = vec4(yep, 0.0, 1.0);
|
||||
}
|
||||
|
@ -0,0 +1,178 @@
|
||||
use color_backtrace;
|
||||
use difference::{Changeset, Difference};
|
||||
use shade_runner::*;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use vulkano::descriptor::descriptor::ShaderStages;
|
||||
use vulkano::format::*;
|
||||
use vulkano::pipeline::shader::ShaderInterfaceDefEntry;
|
||||
|
||||
fn setup() {
|
||||
color_backtrace::install();
|
||||
}
|
||||
|
||||
fn difference(e: &str, t: &str) -> String {
|
||||
let diffs = Changeset::new(&e, &t, "");
|
||||
diffs
|
||||
.diffs
|
||||
.iter()
|
||||
.filter(|d| match d {
|
||||
Difference::Add(_) => true,
|
||||
Difference::Rem(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|d| match d {
|
||||
Difference::Add(a) => format!("add: {}", a),
|
||||
Difference::Rem(a) => format!("remove: {}", a),
|
||||
_ => "".to_string(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn parse<T>(vertex: T, fragment: T) -> shade_runner::Entry
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
{
|
||||
let project_root = std::env::current_dir().expect("failed to get root directory");
|
||||
let mut path = project_root.clone();
|
||||
path.push(PathBuf::from("tests/shaders/"));
|
||||
let mut vertex_path = path.clone();
|
||||
vertex_path.push(vertex);
|
||||
let mut fragment_path = path.clone();
|
||||
fragment_path.push(fragment);
|
||||
let shader = shade_runner::load(vertex_path, fragment_path).expect("Failed to compile");
|
||||
shade_runner::parse(&shader)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shade1() {
|
||||
setup();
|
||||
let target = Entry {
|
||||
frag_input: FragInput { inputs: Vec::new() },
|
||||
frag_output: FragOutput {
|
||||
outputs: vec![ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32B32A32Sfloat,
|
||||
name: Some(Cow::Borrowed("f_color")),
|
||||
}],
|
||||
},
|
||||
frag_layout: FragLayout {
|
||||
stages: ShaderStages {
|
||||
fragment: true,
|
||||
..ShaderStages::none()
|
||||
},
|
||||
layout_data: LayoutData {
|
||||
num_sets: 0,
|
||||
num_bindings: HashMap::new(),
|
||||
},
|
||||
},
|
||||
vert_input: VertInput {
|
||||
inputs: vec![ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32Sfloat,
|
||||
name: Some(Cow::Borrowed("position")),
|
||||
}],
|
||||
},
|
||||
vert_output: VertOutput {
|
||||
outputs: Vec::new(),
|
||||
},
|
||||
vert_layout: VertLayout(ShaderStages {
|
||||
vertex: true,
|
||||
..ShaderStages::none()
|
||||
}),
|
||||
};
|
||||
let entry = parse("vert1.glsl", "frag1.glsl");
|
||||
let entry = format!("{:?}", entry);
|
||||
let target = format!("{:?}", target);
|
||||
assert_eq!(
|
||||
&entry,
|
||||
&target,
|
||||
"\n\nDifference: {}",
|
||||
difference(&entry, &target)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shade2() {
|
||||
setup();
|
||||
let target = Entry {
|
||||
frag_input: FragInput {
|
||||
inputs: vec![
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32B32A32Sfloat,
|
||||
name: Some(Cow::Borrowed("cool")),
|
||||
},
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 1..2,
|
||||
format: Format::R32G32Sfloat,
|
||||
name: Some(Cow::Borrowed("yep")),
|
||||
},
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 2..3,
|
||||
format: Format::R32Sfloat,
|
||||
name: Some(Cow::Borrowed("monkey")),
|
||||
},
|
||||
],
|
||||
},
|
||||
frag_output: FragOutput {
|
||||
outputs: vec![ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32B32A32Sfloat,
|
||||
name: Some(Cow::Borrowed("f_color")),
|
||||
}],
|
||||
},
|
||||
frag_layout: FragLayout {
|
||||
stages: ShaderStages {
|
||||
fragment: true,
|
||||
..ShaderStages::none()
|
||||
},
|
||||
layout_data: LayoutData {
|
||||
num_sets: 0,
|
||||
num_bindings: HashMap::new(),
|
||||
},
|
||||
},
|
||||
vert_input: VertInput {
|
||||
inputs: vec![ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32Sfloat,
|
||||
name: Some(Cow::Borrowed("position")),
|
||||
}],
|
||||
},
|
||||
vert_output: VertOutput {
|
||||
outputs: vec![
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 0..1,
|
||||
format: Format::R32G32B32A32Sfloat,
|
||||
name: Some(Cow::Borrowed("cool")),
|
||||
},
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 1..2,
|
||||
format: Format::R32G32Sfloat,
|
||||
name: Some(Cow::Borrowed("yep")),
|
||||
},
|
||||
ShaderInterfaceDefEntry {
|
||||
location: 2..3,
|
||||
format: Format::R32Sfloat,
|
||||
name: Some(Cow::Borrowed("monkey")),
|
||||
},
|
||||
],
|
||||
},
|
||||
vert_layout: VertLayout(ShaderStages {
|
||||
vertex: true,
|
||||
..ShaderStages::none()
|
||||
}),
|
||||
};
|
||||
let entry = parse("vert2.glsl", "frag2.glsl");
|
||||
let entry = format!("{:?}", entry);
|
||||
let target = format!("{:?}", target);
|
||||
assert_eq!(
|
||||
&entry,
|
||||
&target,
|
||||
"\n\nDifference: {}",
|
||||
difference(&entry, &target)
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in new issue