use crate::{device, pass, Backend};
use std::{borrow::Cow, fmt, io, ops::Range, slice};
mod compute;
mod descriptor;
mod graphics;
mod input_assembler;
mod output_merger;
pub use self::{compute::*, descriptor::*, graphics::*, input_assembler::*, output_merger::*};
#[derive(Clone, Debug, PartialEq, Fail)]
pub enum CreationError {
#[fail(display = "Unknown other error")]
Other,
#[fail(display = "Invalid subpass index: {}", _0)]
InvalidSubpass(pass::SubpassId),
#[fail(display = "Shader compilation error: {}", _0)]
Shader(device::ShaderError),
#[fail(display = "{}", _0)]
OutOfMemory(device::OutOfMemory),
}
impl From<device::OutOfMemory> for CreationError {
fn from(err: device::OutOfMemory) -> Self {
CreationError::OutOfMemory(err)
}
}
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PipelineStage: u32 {
const TOP_OF_PIPE = 0x1;
const DRAW_INDIRECT = 0x2;
const VERTEX_INPUT = 0x4;
const VERTEX_SHADER = 0x8;
const HULL_SHADER = 0x10;
const DOMAIN_SHADER = 0x20;
const GEOMETRY_SHADER = 0x40;
const FRAGMENT_SHADER = 0x80;
const EARLY_FRAGMENT_TESTS = 0x100;
const LATE_FRAGMENT_TESTS = 0x200;
const COLOR_ATTACHMENT_OUTPUT = 0x400;
const COMPUTE_SHADER = 0x800;
const TRANSFER = 0x1000;
const BOTTOM_OF_PIPE = 0x2000;
const HOST = 0x4000;
}
);
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ShaderStageFlags: u32 {
const VERTEX = 0x1;
const HULL = 0x2;
const DOMAIN = 0x4;
const GEOMETRY = 0x8;
const FRAGMENT = 0x10;
const COMPUTE = 0x20;
const GRAPHICS = Self::VERTEX.bits | Self::HULL.bits |
Self::DOMAIN.bits | Self::GEOMETRY.bits | Self::FRAGMENT.bits;
const ALL = Self::GRAPHICS.bits | Self::COMPUTE.bits;
}
);
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum Stage {
Vertex,
Hull,
Domain,
Geometry,
Fragment,
Compute,
}
impl From<Stage> for ShaderStageFlags {
fn from(stage: Stage) -> Self {
match stage {
Stage::Vertex => ShaderStageFlags::VERTEX,
Stage::Hull => ShaderStageFlags::HULL,
Stage::Domain => ShaderStageFlags::DOMAIN,
Stage::Geometry => ShaderStageFlags::GEOMETRY,
Stage::Fragment => ShaderStageFlags::FRAGMENT,
Stage::Compute => ShaderStageFlags::COMPUTE,
}
}
}
impl fmt::Display for Stage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
Stage::Vertex => "vertex",
Stage::Hull => "hull",
Stage::Domain => "domain",
Stage::Geometry => "geometry",
Stage::Fragment => "fragment",
Stage::Compute => "compute",
})
}
}
#[derive(Debug)]
pub struct EntryPoint<'a, B: Backend> {
pub entry: &'a str,
pub module: &'a B::ShaderModule,
pub specialization: Specialization<'a>,
}
impl<'a, B: Backend> Clone for EntryPoint<'a, B> {
fn clone(&self) -> Self {
EntryPoint {
entry: self.entry,
module: self.module,
specialization: self.specialization.clone(),
}
}
}
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PipelineCreationFlags: u32 {
const DISABLE_OPTIMIZATION = 0x1;
const ALLOW_DERIVATIVES = 0x2;
}
);
#[derive(Debug)]
pub enum BasePipeline<'a, P: 'a> {
Pipeline(&'a P),
Index(usize),
None,
}
#[derive(Debug, Clone)]
pub struct SpecializationConstant {
pub id: u32,
pub range: Range<u16>,
}
#[derive(Debug, Clone)]
pub struct Specialization<'a> {
pub constants: Cow<'a, [SpecializationConstant]>,
pub data: Cow<'a, [u8]>,
}
impl Specialization<'_> {
pub const EMPTY: Self = Specialization {
constants: Cow::Borrowed(&[]),
data: Cow::Borrowed(&[]),
};
}
impl Default for Specialization<'_> {
fn default() -> Self {
Specialization::EMPTY
}
}
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct SpecializationStorage {
constants: Vec<SpecializationConstant>,
data: Vec<u8>,
}
#[doc(hidden)]
pub trait SpecConstList: Sized {
fn fold(self, storage: &mut SpecializationStorage);
}
impl<T> From<T> for Specialization<'_>
where
T: SpecConstList,
{
fn from(list: T) -> Self {
let mut storage = SpecializationStorage::default();
list.fold(&mut storage);
Specialization {
data: Cow::Owned(storage.data),
constants: Cow::Owned(storage.constants),
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct SpecConstListNil;
#[doc(hidden)]
#[derive(Debug)]
pub struct SpecConstListCons<H, T> {
pub head: (u32, H),
pub tail: T,
}
impl SpecConstList for SpecConstListNil {
fn fold(self, _storage: &mut SpecializationStorage) {}
}
impl<H, T> SpecConstList for SpecConstListCons<H, T>
where
T: SpecConstList,
{
fn fold(self, storage: &mut SpecializationStorage) {
let size = std::mem::size_of::<H>();
assert!(storage.data.len() + size <= u16::max_value() as usize);
let offset = storage.data.len() as u16;
storage.data.extend_from_slice(unsafe {
slice::from_raw_parts(&self.head.1 as *const H as *const u8, size)
});
storage.constants.push(SpecializationConstant {
id: self.head.0,
range: offset .. offset + size as u16,
});
self.tail.fold(storage)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum State<T> {
Static(T),
Dynamic,
}
impl<T> State<T> {
pub fn static_or(self, default: T) -> T {
match self {
State::Static(v) => v,
State::Dynamic => default,
}
}
pub fn is_static(self) -> bool {
match self {
State::Static(_) => true,
State::Dynamic => false,
}
}
pub fn is_dynamic(self) -> bool {
!self.is_static()
}
}
#[macro_export]
macro_rules! spec_const_list {
(@ $(,)?) => {
$crate::pso::SpecConstListNil
};
(@ $head_id:expr => $head_constant:expr $(,$tail_id:expr => $tail_constant:expr)* $(,)?) => {
$crate::pso::SpecConstListCons {
head: ($head_id, $head_constant),
tail: $crate::spec_const_list!(@ $($tail_id:expr => $tail_constant:expr),*),
}
};
($($id:expr => $constant:expr),* $(,)?) => {
$crate::spec_const_list!(@ $($id => $constant),*).into()
};
($($constant:expr),* $(,)?) => {
{
let mut counter = 0;
$crate::spec_const_list!(@ $({ counter += 1; counter - 1 } => $constant),*).into()
}
};
}
pub fn read_spirv<R: io::Read + io::Seek>(mut x: R) -> io::Result<Vec<u32>> {
let size = x.seek(io::SeekFrom::End(0))?;
if size % 4 != 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"input length not divisible by 4",
));
}
if size > usize::max_value() as u64 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "input too long"));
}
let words = (size / 4) as usize;
let mut result = Vec::<u32>::with_capacity(words);
x.seek(io::SeekFrom::Start(0))?;
unsafe {
x.read_exact(slice::from_raw_parts_mut(
result.as_mut_ptr() as *mut u8,
words * 4,
))?;
result.set_len(words);
}
const MAGIC_NUMBER: u32 = 0x07230203;
if result.len() > 0 && result[0] == MAGIC_NUMBER.swap_bytes() {
for word in &mut result {
*word = word.swap_bytes();
}
}
if result.len() == 0 || result[0] != MAGIC_NUMBER {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"input missing SPIR-V magic number",
));
}
Ok(result)
}