mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Add draft for SPIR-V parser
This commit is contained in:
parent
5c6cf93bd7
commit
f9f014c789
2
shader-parser/.gitignore
vendored
Normal file
2
shader-parser/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
target
|
||||||
|
Cargo.lock
|
4
shader-parser/Cargo.toml
Normal file
4
shader-parser/Cargo.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "shader-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
37
shader-parser/src/lib.rs
Normal file
37
shader-parser/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::io::Error as IoError;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
pub use parse::ParseError;
|
||||||
|
|
||||||
|
mod parse;
|
||||||
|
|
||||||
|
pub fn reflect<R>(mut spirv: R) -> Result<String, Error>
|
||||||
|
where R: Read
|
||||||
|
{
|
||||||
|
let mut data = Vec::new();
|
||||||
|
try!(spirv.read_to_end(&mut data));
|
||||||
|
|
||||||
|
// now parsing the document
|
||||||
|
let doc = try!(parse::parse_spirv(&data));
|
||||||
|
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Error {
|
||||||
|
IoError(IoError),
|
||||||
|
ParseError(ParseError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IoError> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(err: IoError) -> Error {
|
||||||
|
Error::IoError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseError> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(err: ParseError) -> Error {
|
||||||
|
Error::ParseError(err)
|
||||||
|
}
|
||||||
|
}
|
298
shader-parser/src/parse.rs
Normal file
298
shader-parser/src/parse.rs
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
|
||||||
|
pub fn parse_spirv(data: &[u8]) -> Result<Spirv, ParseError> {
|
||||||
|
if data.len() < 20 {
|
||||||
|
return Err(ParseError::MissingHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to determine whether we are in big endian order or little endian order depending
|
||||||
|
// on the magic number at the start of the file
|
||||||
|
let data = if data[0] == 0x07 && data[1] == 0x23 && data[2] == 0x02 && data[3] == 0x03 {
|
||||||
|
// big endian
|
||||||
|
data.chunks(4).map(|c| {
|
||||||
|
((c[0] as u32) << 24) | ((c[1] as u32) << 16) | ((c[2] as u32) << 8) | c[3] as u32
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
|
||||||
|
} else if data[3] == 0x07 && data[2] == 0x23 && data[1] == 0x02 && data[0] == 0x03 {
|
||||||
|
// little endian
|
||||||
|
data.chunks(4).map(|c| {
|
||||||
|
((c[3] as u32) << 24) | ((c[2] as u32) << 16) | ((c[1] as u32) << 8) | c[0] as u32
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingHeader);
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_u32s(&data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_u32s(i: &[u32]) -> Result<Spirv, ParseError> {
|
||||||
|
if i.len() < 5 {
|
||||||
|
return Err(ParseError::MissingHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if i[0] != 0x07230203 {
|
||||||
|
return Err(ParseError::WrongHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = (((i[1] & 0x00ff0000) >> 16) as u8, ((i[1] & 0x0000ff00) >> 8) as u8);
|
||||||
|
|
||||||
|
let instructions = {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
let mut i = &i[5..];
|
||||||
|
while i.len() >= 1 {
|
||||||
|
let (instruction, rest) = try!(parse_instruction(i));
|
||||||
|
ret.push(instruction);
|
||||||
|
i = rest;
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Spirv {
|
||||||
|
version: version,
|
||||||
|
bound: i[3],
|
||||||
|
instructions: instructions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ParseError {
|
||||||
|
MissingHeader,
|
||||||
|
WrongHeader,
|
||||||
|
IncompleteInstruction,
|
||||||
|
UnknownCapability(u32),
|
||||||
|
UnknownExecutionModel(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Spirv {
|
||||||
|
pub version: (u8, u8),
|
||||||
|
pub bound: u32,
|
||||||
|
pub instructions: Vec<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Instruction {
|
||||||
|
Unknown(u16, Vec<u32>),
|
||||||
|
Nop,
|
||||||
|
ExtInstImport { result_id: u32, name: String },
|
||||||
|
EntryPoint { execution: ExecutionModel, id: u32, name: String, interface: Vec<u32> },
|
||||||
|
Capability(Capability),
|
||||||
|
FunctionEnd,
|
||||||
|
Kill,
|
||||||
|
Return,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_instruction(i: &[u32]) -> Result<(Instruction, &[u32]), ParseError> {
|
||||||
|
assert!(i.len() >= 1);
|
||||||
|
|
||||||
|
let word_count = (i[0] >> 16) as usize;
|
||||||
|
assert!(word_count >= 1);
|
||||||
|
let opcode = (i[0] & 0xffff) as u16;
|
||||||
|
|
||||||
|
if i.len() < word_count {
|
||||||
|
return Err(ParseError::IncompleteInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
let opcode = try!(decode_instruction(opcode, &i[1 .. word_count]));
|
||||||
|
Ok((opcode, &i[word_count..]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_instruction(opcode: u16, operands: &[u32]) -> Result<Instruction, ParseError> {
|
||||||
|
Ok(match opcode {
|
||||||
|
0 => Instruction::Nop,
|
||||||
|
11 => Instruction::ExtInstImport {
|
||||||
|
result_id: operands[0],
|
||||||
|
name: parse_string(&operands[1..]).0
|
||||||
|
},
|
||||||
|
15 => {
|
||||||
|
let (n, r) = parse_string(&operands[2..]);
|
||||||
|
Instruction::EntryPoint {
|
||||||
|
execution: try!(ExecutionModel::from_num(operands[0])),
|
||||||
|
id: operands[1],
|
||||||
|
name: n,
|
||||||
|
interface: r.to_owned(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
17 => Instruction::Capability(try!(Capability::from_num(operands[0]))),
|
||||||
|
56 => Instruction::FunctionEnd,
|
||||||
|
252 => Instruction::Kill,
|
||||||
|
253 => Instruction::Return,
|
||||||
|
_ => Instruction::Unknown(opcode, operands.to_owned()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_string(data: &[u32]) -> (String, &[u32]) {
|
||||||
|
let bytes = data.iter().flat_map(|&n| {
|
||||||
|
let b1 = (n & 0xff) as u8;
|
||||||
|
let b2 = ((n >> 8) & 0xff) as u8;
|
||||||
|
let b3 = ((n >> 16) & 0xff) as u8;
|
||||||
|
let b4 = ((n >> 24) & 0xff) as u8;
|
||||||
|
vec![b1, b2, b3, b4].into_iter()
|
||||||
|
}).take_while(|&b| b != 0).collect::<Vec<u8>>();
|
||||||
|
|
||||||
|
let r = 1 + bytes.len() / 4;
|
||||||
|
let s = String::from_utf8(bytes).expect("Shader content is not UTF-8");
|
||||||
|
|
||||||
|
(s, &data[r..])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Capability {
|
||||||
|
Matrix,
|
||||||
|
Shader,
|
||||||
|
Geometry,
|
||||||
|
Tessellation,
|
||||||
|
Addresses,
|
||||||
|
Linkage,
|
||||||
|
Kernel,
|
||||||
|
Vector16,
|
||||||
|
Float16Buffer,
|
||||||
|
Float16,
|
||||||
|
Float64,
|
||||||
|
Int64,
|
||||||
|
Int64Atomics,
|
||||||
|
ImageBasic,
|
||||||
|
ImageReadWrite,
|
||||||
|
ImageMipmap,
|
||||||
|
Pipes,
|
||||||
|
Groups,
|
||||||
|
DeviceEnqueue,
|
||||||
|
LiteralSampler,
|
||||||
|
AtomicStorage,
|
||||||
|
Int16,
|
||||||
|
TessellationPointSize,
|
||||||
|
GeometryPointSize,
|
||||||
|
ImageGatherExtended,
|
||||||
|
StorageImageMultisample,
|
||||||
|
UniformBufferArrayDynamicIndexing,
|
||||||
|
SampledImageArrayDynamicIndexing,
|
||||||
|
StorageBufferArrayDynamicIndexing,
|
||||||
|
StorageImageArrayDynamicIndexing,
|
||||||
|
ClipDistance,
|
||||||
|
CullDistance,
|
||||||
|
ImageCubeArray,
|
||||||
|
SampleRateShading,
|
||||||
|
ImageRect,
|
||||||
|
SampledRect,
|
||||||
|
GenericPointer,
|
||||||
|
Int8,
|
||||||
|
InputAttachment,
|
||||||
|
SparseResidency,
|
||||||
|
MinLod,
|
||||||
|
Sampled1D,
|
||||||
|
Image1D,
|
||||||
|
SampledCubeArray,
|
||||||
|
SampledBuffer,
|
||||||
|
ImageBuffer,
|
||||||
|
ImageMSArray,
|
||||||
|
StorageImageExtendedFormats,
|
||||||
|
ImageQuery,
|
||||||
|
DerivativeControl,
|
||||||
|
InterpolationFunction,
|
||||||
|
TransformFeedback,
|
||||||
|
GeometryStreams,
|
||||||
|
StorageImageReadWithoutFormat,
|
||||||
|
StorageImageWriteWithoutFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Capability {
|
||||||
|
fn from_num(num: u32) -> Result<Capability, ParseError> {
|
||||||
|
match num {
|
||||||
|
0 => Ok(Capability::Matrix),
|
||||||
|
1 => Ok(Capability::Shader),
|
||||||
|
2 => Ok(Capability::Geometry),
|
||||||
|
3 => Ok(Capability::Tessellation),
|
||||||
|
4 => Ok(Capability::Addresses),
|
||||||
|
5 => Ok(Capability::Linkage),
|
||||||
|
6 => Ok(Capability::Kernel),
|
||||||
|
7 => Ok(Capability::Vector16),
|
||||||
|
8 => Ok(Capability::Float16Buffer),
|
||||||
|
9 => Ok(Capability::Float16),
|
||||||
|
10 => Ok(Capability::Float64),
|
||||||
|
11 => Ok(Capability::Int64),
|
||||||
|
12 => Ok(Capability::Int64Atomics),
|
||||||
|
13 => Ok(Capability::ImageBasic),
|
||||||
|
14 => Ok(Capability::ImageReadWrite),
|
||||||
|
15 => Ok(Capability::ImageMipmap),
|
||||||
|
17 => Ok(Capability::Pipes),
|
||||||
|
18 => Ok(Capability::Groups),
|
||||||
|
19 => Ok(Capability::DeviceEnqueue),
|
||||||
|
20 => Ok(Capability::LiteralSampler),
|
||||||
|
21 => Ok(Capability::AtomicStorage),
|
||||||
|
22 => Ok(Capability::Int16),
|
||||||
|
23 => Ok(Capability::TessellationPointSize),
|
||||||
|
24 => Ok(Capability::GeometryPointSize),
|
||||||
|
25 => Ok(Capability::ImageGatherExtended),
|
||||||
|
27 => Ok(Capability::StorageImageMultisample),
|
||||||
|
28 => Ok(Capability::UniformBufferArrayDynamicIndexing),
|
||||||
|
29 => Ok(Capability::SampledImageArrayDynamicIndexing),
|
||||||
|
30 => Ok(Capability::StorageBufferArrayDynamicIndexing),
|
||||||
|
31 => Ok(Capability::StorageImageArrayDynamicIndexing),
|
||||||
|
32 => Ok(Capability::ClipDistance),
|
||||||
|
33 => Ok(Capability::CullDistance),
|
||||||
|
34 => Ok(Capability::ImageCubeArray),
|
||||||
|
35 => Ok(Capability::SampleRateShading),
|
||||||
|
36 => Ok(Capability::ImageRect),
|
||||||
|
37 => Ok(Capability::SampledRect),
|
||||||
|
38 => Ok(Capability::GenericPointer),
|
||||||
|
39 => Ok(Capability::Int8),
|
||||||
|
40 => Ok(Capability::InputAttachment),
|
||||||
|
41 => Ok(Capability::SparseResidency),
|
||||||
|
42 => Ok(Capability::MinLod),
|
||||||
|
43 => Ok(Capability::Sampled1D),
|
||||||
|
44 => Ok(Capability::Image1D),
|
||||||
|
45 => Ok(Capability::SampledCubeArray),
|
||||||
|
46 => Ok(Capability::SampledBuffer),
|
||||||
|
47 => Ok(Capability::ImageBuffer),
|
||||||
|
48 => Ok(Capability::ImageMSArray),
|
||||||
|
49 => Ok(Capability::StorageImageExtendedFormats),
|
||||||
|
50 => Ok(Capability::ImageQuery),
|
||||||
|
51 => Ok(Capability::DerivativeControl),
|
||||||
|
52 => Ok(Capability::InterpolationFunction),
|
||||||
|
53 => Ok(Capability::TransformFeedback),
|
||||||
|
54 => Ok(Capability::GeometryStreams),
|
||||||
|
55 => Ok(Capability::StorageImageReadWithoutFormat),
|
||||||
|
56 => Ok(Capability::StorageImageWriteWithoutFormat),
|
||||||
|
_ => Err(ParseError::UnknownCapability(num)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ExecutionModel {
|
||||||
|
Vertex,
|
||||||
|
TessellationControl,
|
||||||
|
TessellationEvaluation,
|
||||||
|
Geometry,
|
||||||
|
Fragment,
|
||||||
|
GLCompute,
|
||||||
|
Kernel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutionModel {
|
||||||
|
fn from_num(num: u32) -> Result<ExecutionModel, ParseError> {
|
||||||
|
match num {
|
||||||
|
0 => Ok(ExecutionModel::Vertex),
|
||||||
|
1 => Ok(ExecutionModel::TessellationControl),
|
||||||
|
2 => Ok(ExecutionModel::TessellationEvaluation),
|
||||||
|
3 => Ok(ExecutionModel::Geometry),
|
||||||
|
4 => Ok(ExecutionModel::Fragment),
|
||||||
|
5 => Ok(ExecutionModel::GLCompute),
|
||||||
|
6 => Ok(ExecutionModel::Kernel),
|
||||||
|
_ => Err(ParseError::UnknownExecutionModel(num)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use parse;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let data = include_bytes!("../tests/frag.spv");
|
||||||
|
let doc = parse::parse_spirv(data).unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", doc);
|
||||||
|
}
|
||||||
|
}
|
BIN
shader-parser/tests/frag.spv
Normal file
BIN
shader-parser/tests/frag.spv
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user