1
0
mirror of synced 2025-11-09 21:07:12 +00:00

initial commit

This commit is contained in:
Tom Gowan
2019-04-26 13:00:38 +10:00
commit 0755b4f807
16 changed files with 651 additions and 0 deletions

26
src/compiler.rs Normal file
View File

@@ -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())
}

4
src/error.rs Normal file
View File

@@ -0,0 +1,4 @@
#[derive(Debug)]
pub enum Error {
Compile(shaderc::Error),
}

125
src/layouts.rs Normal file
View File

@@ -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
}
}

32
src/lib.rs Normal file
View File

@@ -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)
}

90
src/reflection.rs Normal file
View File

@@ -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")
}

100
src/srvk.rs Normal file
View File

@@ -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 }
}
}