use crate::{
binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError},
device::{DeviceError, RenderPassContext},
hub::Resource,
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
validation, Label, LifeGuard, Stored,
};
use std::borrow::Cow;
use thiserror::Error;
#[derive(Debug)]
pub enum ShaderModuleSource<'a> {
SpirV(Cow<'a, [u32]>),
Wgsl(Cow<'a, str>),
Naga(naga::Module),
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ShaderModuleDescriptor<'a> {
pub label: Label<'a>,
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub flags: wgt::ShaderFlags,
}
#[derive(Debug)]
pub struct ShaderModule<B: hal::Backend> {
pub(crate) raw: B::ShaderModule,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) interface: Option<validation::Interface>,
#[cfg(debug_assertions)]
pub(crate) label: String,
}
impl<B: hal::Backend> Resource for ShaderModule<B> {
const TYPE: &'static str = "ShaderModule";
fn life_guard(&self) -> &LifeGuard {
unreachable!()
}
fn label(&self) -> &str {
#[cfg(debug_assertions)]
return &self.label;
#[cfg(not(debug_assertions))]
return "";
}
}
#[derive(Clone, Debug, Error)]
pub enum CreateShaderModuleError {
#[error("Failed to parse WGSL")]
Parsing,
#[error(transparent)]
Device(#[from] DeviceError),
#[error(transparent)]
Validation(#[from] naga::proc::ValidationError),
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ProgrammableStageDescriptor<'a> {
pub module: ShaderModuleId,
pub entry_point: Cow<'a, str>,
}
pub type ImplicitBindGroupCount = u8;
#[derive(Clone, Debug, Error)]
pub enum ImplicitLayoutError {
#[error("missing IDs for deriving {0} bind groups")]
MissingIds(ImplicitBindGroupCount),
#[error("unable to reflect the shader {0:?} interface")]
ReflectionError(wgt::ShaderStage),
#[error(transparent)]
BindGroup(#[from] CreateBindGroupLayoutError),
#[error(transparent)]
Pipeline(#[from] CreatePipelineLayoutError),
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ComputePipelineDescriptor<'a> {
pub label: Label<'a>,
pub layout: Option<PipelineLayoutId>,
pub stage: ProgrammableStageDescriptor<'a>,
}
#[derive(Clone, Debug, Error)]
pub enum CreateComputePipelineError {
#[error(transparent)]
Device(#[from] DeviceError),
#[error("pipeline layout is invalid")]
InvalidLayout,
#[error("unable to derive an implicit layout")]
Implicit(#[from] ImplicitLayoutError),
#[error(transparent)]
Stage(validation::StageError),
}
#[derive(Debug)]
pub struct ComputePipeline<B: hal::Backend> {
pub(crate) raw: B::ComputePipeline,
pub(crate) layout_id: Stored<PipelineLayoutId>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Resource for ComputePipeline<B> {
const TYPE: &'static str = "ComputePipeline";
fn life_guard(&self) -> &LifeGuard {
&self.life_guard
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexBufferLayout<'a> {
pub array_stride: wgt::BufferAddress,
pub step_mode: wgt::InputStepMode,
pub attributes: Cow<'a, [wgt::VertexAttribute]>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexState<'a> {
pub stage: ProgrammableStageDescriptor<'a>,
pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct FragmentState<'a> {
pub stage: ProgrammableStageDescriptor<'a>,
pub targets: Cow<'a, [wgt::ColorTargetState]>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderPipelineDescriptor<'a> {
pub label: Label<'a>,
pub layout: Option<PipelineLayoutId>,
pub vertex: VertexState<'a>,
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub primitive: wgt::PrimitiveState,
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub depth_stencil: Option<wgt::DepthStencilState>,
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub multisample: wgt::MultisampleState,
pub fragment: Option<FragmentState<'a>>,
}
#[derive(Clone, Debug, Error)]
pub enum CreateRenderPipelineError {
#[error(transparent)]
Device(#[from] DeviceError),
#[error("pipelie layout is invalid")]
InvalidLayout,
#[error("unable to derive an implicit layout")]
Implicit(#[from] ImplicitLayoutError),
#[error("missing output at index {index}")]
MissingOutput { index: u8 },
#[error("incompatible output format at index {index}")]
IncompatibleOutputFormat { index: u8 },
#[error("invalid sample count {0}")]
InvalidSampleCount(u32),
#[error("vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
UnalignedVertexStride {
index: u32,
stride: wgt::BufferAddress,
},
#[error("vertex attribute at location {location} has invalid offset {offset}")]
InvalidVertexAttributeOffset {
location: wgt::ShaderLocation,
offset: wgt::BufferAddress,
},
#[error("missing required device features {0:?}")]
MissingFeature(wgt::Features),
#[error("error in stage {flag:?}")]
Stage {
flag: wgt::ShaderStage,
#[source]
error: validation::StageError,
},
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct PipelineFlags: u32 {
const BLEND_COLOR = 1;
const STENCIL_REFERENCE = 2;
const WRITES_DEPTH_STENCIL = 4;
}
}
#[derive(Debug)]
pub struct RenderPipeline<B: hal::Backend> {
pub(crate) raw: B::GraphicsPipeline,
pub(crate) layout_id: Stored<PipelineLayoutId>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) strip_index_format: Option<wgt::IndexFormat>,
pub(crate) vertex_strides: Vec<(wgt::BufferAddress, wgt::InputStepMode)>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Resource for RenderPipeline<B> {
const TYPE: &'static str = "RenderPipeline";
fn life_guard(&self) -> &LifeGuard {
&self.life_guard
}
}