use alloc::borrow::Cow;
use bevy_asset::Handle;
use bevy_derive::Deref;
use bevy_mesh::VertexBufferLayout;
use bevy_shader::{CachedPipelineId, Shader, ShaderDefVal};
use core::iter;
use thiserror::Error;
use wgpu_types::{
BindGroupLayoutEntry, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState,
};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct BindGroupLayoutDescriptor {
pub label: Cow<'static, str>,
pub entries: Vec<BindGroupLayoutEntry>,
}
impl BindGroupLayoutDescriptor {
pub fn new(label: impl Into<Cow<'static, str>>, entries: &[BindGroupLayoutEntry]) -> Self {
Self {
label: label.into(),
entries: entries.into(),
}
}
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct RenderPipelineDescriptor {
pub label: Option<Cow<'static, str>>,
pub layout: Vec<BindGroupLayoutDescriptor>,
pub immediate_size: u32,
pub vertex: VertexState,
pub primitive: PrimitiveState,
pub depth_stencil: Option<DepthStencilState>,
pub multisample: MultisampleState,
pub fragment: Option<FragmentState>,
pub zero_initialize_workgroup_memory: bool,
}
#[derive(Copy, Clone, Debug, Error)]
#[error("RenderPipelineDescriptor has no FragmentState configured")]
pub struct NoFragmentStateError;
impl RenderPipelineDescriptor {
pub fn fragment_mut(&mut self) -> Result<&mut FragmentState, NoFragmentStateError> {
self.fragment.as_mut().ok_or(NoFragmentStateError)
}
pub fn set_layout(&mut self, index: usize, layout: BindGroupLayoutDescriptor) {
filling_set_at(&mut self.layout, index, bevy_utils::default(), layout);
}
}
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct VertexState {
pub shader: Handle<Shader>,
pub shader_defs: Vec<ShaderDefVal>,
pub entry_point: Option<Cow<'static, str>>,
pub buffers: Vec<VertexBufferLayout>,
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct FragmentState {
pub shader: Handle<Shader>,
pub shader_defs: Vec<ShaderDefVal>,
pub entry_point: Option<Cow<'static, str>>,
pub targets: Vec<Option<ColorTargetState>>,
}
impl FragmentState {
pub fn set_target(&mut self, index: usize, target: ColorTargetState) {
filling_set_at(&mut self.targets, index, None, Some(target));
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct ComputePipelineDescriptor {
pub label: Option<Cow<'static, str>>,
pub layout: Vec<BindGroupLayoutDescriptor>,
pub immediate_size: u32,
pub shader: Handle<Shader>,
pub shader_defs: Vec<ShaderDefVal>,
pub entry_point: Option<Cow<'static, str>>,
pub zero_initialize_workgroup_memory: bool,
}
fn filling_set_at<T: Clone>(vec: &mut Vec<T>, index: usize, filler: T, value: T) {
let num_to_fill = (index + 1).saturating_sub(vec.len());
vec.extend(iter::repeat_n(filler, num_to_fill));
vec[index] = value;
}
#[derive(Debug)]
pub enum PipelineDescriptor {
RenderPipelineDescriptor(Box<RenderPipelineDescriptor>),
ComputePipelineDescriptor(Box<ComputePipelineDescriptor>),
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Deref)]
pub struct CachedRenderPipelineId(CachedPipelineId);
impl CachedRenderPipelineId {
pub const INVALID: Self = CachedRenderPipelineId(usize::MAX);
#[inline]
pub fn new(id: usize) -> Self {
Self(id)
}
#[inline]
pub fn id(&self) -> usize {
self.0
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct CachedComputePipelineId(CachedPipelineId);
impl CachedComputePipelineId {
pub const INVALID: Self = CachedComputePipelineId(usize::MAX);
#[inline]
pub fn new(id: usize) -> Self {
Self(id)
}
#[inline]
pub fn id(&self) -> usize {
self.0
}
}