|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
//! SPIR-V shaders.
|
|
|
|
|
|
|
|
|
|
use crate::types::Conv; |
|
|
|
|
|
|
|
|
|
bitflags::bitflags! { |
|
|
|
|
/// A flag set of shader stages.
|
|
|
|
|
pub struct ShaderStage: u8 { |
|
|
|
@ -12,14 +14,14 @@ bitflags::bitflags! {
|
|
|
|
|
/// A SPIR-V IR module.
|
|
|
|
|
pub struct Module { |
|
|
|
|
pub code: Vec<u32>, |
|
|
|
|
pub size: usize, |
|
|
|
|
pub name: String, |
|
|
|
|
pub stag: ShaderStage, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// The error type which is returned from reading a shader program.
|
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
pub enum Err { |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Text(#[from] std::str::Utf8Error), |
|
|
|
|
#[error("{}", err.emit_to_string(src))] |
|
|
|
|
Parse { err: naga::front::wgsl::ParseError, src: String }, |
|
|
|
|
#[error(transparent)] |
|
|
|
@ -29,21 +31,59 @@ pub enum Err {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Module { |
|
|
|
|
/// Reads a SPIR-V IR or WGSL source from a buffer.
|
|
|
|
|
pub fn compile(src: &[u8]) -> Result<Self, Err> { |
|
|
|
|
if src[0..4] == [0x07, 0x23, 0x02, 0x03] |
|
|
|
|
|| src[0..4] == [0x03, 0x02, 0x23, 0x07] |
|
|
|
|
{ |
|
|
|
|
Self::read_spv(src) |
|
|
|
|
} else { |
|
|
|
|
Self::compile_wgsl(std::str::from_utf8(src)?) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Reads SPIR-V IR in from a buffer.
|
|
|
|
|
pub fn read(bytecode: &[u8], name: &str, stag: ShaderStage) -> Self { |
|
|
|
|
fn read_spv(bytecode: &[u8]) -> Result<Self, Err> { |
|
|
|
|
let read_word = if bytecode[0..4] == [0x07, 0x23, 0x02, 0x03] { |
|
|
|
|
super::read::u32be |
|
|
|
|
} else { |
|
|
|
|
super::read::u32le |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let mut code = Vec::with_capacity(bytecode.len() / 4); |
|
|
|
|
|
|
|
|
|
for word in bytecode.chunks_exact(4) { |
|
|
|
|
code.push(super::read::u32le(word, 0)); |
|
|
|
|
code.push(read_word(word, 0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let size = code.len() * 4; |
|
|
|
|
let mut stag = ShaderStage::empty(); |
|
|
|
|
let mut it = code.iter().peekable(); |
|
|
|
|
it.nth(4); |
|
|
|
|
while let Some(w) = it.next() { |
|
|
|
|
match w & 0xFFFF { |
|
|
|
|
| 15 => { |
|
|
|
|
if let Some(model) = it.peek() { |
|
|
|
|
stag |= match model { |
|
|
|
|
| 0 => ShaderStage::VERTEX, |
|
|
|
|
| 4 => ShaderStage::FRAGMENT, |
|
|
|
|
| 5 => ShaderStage::COMPUTE, |
|
|
|
|
| _ => ShaderStage::empty(), |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
| _ => {} |
|
|
|
|
} |
|
|
|
|
let n = w & 0xFFFF_0000 >> 16; |
|
|
|
|
if n > 0 { |
|
|
|
|
it.nth(usize::conv(n) - 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Self { code, size, name: name.to_owned(), stag } |
|
|
|
|
Ok(Self { code, stag }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Compiles WGSL source to SPIR-V IR.
|
|
|
|
|
pub fn compile(source: &str, name: &str) -> Result<Self, Err> { |
|
|
|
|
fn compile_wgsl(source: &str) -> Result<Self, Err> { |
|
|
|
|
use naga::back::spv; |
|
|
|
|
|
|
|
|
|
let modu = naga::front::wgsl::parse_str(source) |
|
|
|
@ -79,9 +119,7 @@ impl Module {
|
|
|
|
|
|
|
|
|
|
let code = spv::write_vec(&modu, &info, &opts)?; |
|
|
|
|
|
|
|
|
|
let size = code.len() * 4; |
|
|
|
|
|
|
|
|
|
Ok(Self { code, size, name: name.to_owned(), stag }) |
|
|
|
|
Ok(Self { code, stag }) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|