use crate::{
binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError},
device::{DeviceError, RenderPassContext},
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
validation::StageError,
Label, LifeGuard, RefCount, Stored,
};
use std::borrow::{Borrow, Cow};
use thiserror::Error;
use wgt::{BufferAddress, IndexFormat, InputStepMode};
#[repr(C)]
#[derive(Debug)]
pub enum ShaderModuleSource<'a> {
SpirV(Cow<'a, [u32]>),
Wgsl(Cow<'a, str>),
Naga(naga::Module),
}
#[derive(Debug)]
pub struct ShaderModule<B: hal::Backend> {
pub(crate) raw: B::ShaderModule,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) module: Option<naga::Module>,
}
#[derive(Clone, Debug, Error)]
pub enum CreateShaderModuleError {
#[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 compute_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(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> Borrow<RefCount> for ComputePipeline<B> {
fn borrow(&self) -> &RefCount {
self.life_guard.ref_count.as_ref().unwrap()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexBufferDescriptor<'a> {
pub stride: BufferAddress,
pub step_mode: InputStepMode,
pub attributes: Cow<'a, [wgt::VertexAttributeDescriptor]>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexStateDescriptor<'a> {
pub index_format: IndexFormat,
pub vertex_buffers: Cow<'a, [VertexBufferDescriptor<'a>]>,
}
#[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_stage: ProgrammableStageDescriptor<'a>,
pub fragment_stage: Option<ProgrammableStageDescriptor<'a>>,
pub rasterization_state: Option<wgt::RasterizationStateDescriptor>,
pub primitive_topology: wgt::PrimitiveTopology,
pub color_states: Cow<'a, [wgt::ColorStateDescriptor]>,
pub depth_stencil_state: Option<wgt::DepthStencilStateDescriptor>,
pub vertex_state: VertexStateDescriptor<'a>,
pub sample_count: u32,
pub sample_mask: u32,
pub alpha_to_coverage_enabled: bool,
}
#[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("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: BufferAddress },
#[error("vertex attribute at location {location} has invalid offset {offset}")]
InvalidVertexAttributeOffset {
location: wgt::ShaderLocation,
offset: BufferAddress,
},
#[error("missing required device features {0:?}")]
MissingFeature(wgt::Features),
#[error("error in stage {flag:?}: {error}")]
Stage {
flag: wgt::ShaderStage,
error: 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) index_format: IndexFormat,
pub(crate) vertex_strides: Vec<(BufferAddress, InputStepMode)>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Borrow<RefCount> for RenderPipeline<B> {
fn borrow(&self) -> &RefCount {
self.life_guard.ref_count.as_ref().unwrap()
}
}