use std::{
any::TypeId,
marker::PhantomData,
ops::Deref,
};
use crate::wgpu;
#[cfg(all(feature = "wgpu-29", not(feature = "wgpu-30")))]
#[doc(hidden)]
#[macro_export]
macro_rules! vertices {
($struct:ty, $($vertexty:ty),*) => {
use ::std::sync::LazyLock;
static VERTICES: LazyLock<<$struct as $crate::pipeline::MewPipeline>::VertexArray<$crate::wgpu::VertexBufferLayout<'static>>> = LazyLock::new(|| {
#[allow(unused_imports)]
use $crate::vertexstruct::MewVertexStruct;
[ $( <$vertexty>::vertex_layout(), )* ]
});
};
}
#[cfg(feature = "wgpu-30")]
#[doc(hidden)]
#[macro_export]
macro_rules! vertices {
($struct:ty, $($vertexty:ty),*) => {
use ::std::sync::LazyLock;
static VERTICES: LazyLock<<$struct as $crate::pipeline::MewPipeline>::VertexArray<Option<$crate::wgpu::VertexBufferLayout<'static>>>> = LazyLock::new(|| {
#[allow(unused_imports)]
use $crate::vertexstruct::MewVertexStruct;
[ $( Some(<$vertexty>::vertex_layout()), )* ]
});
};
}
#[cfg(any(feature = "wgpu-29", feature = "wgpu-30"))]
pub use vertices;
#[macro_export]
macro_rules! pipeline {
{ $struct:ident { $($key:tt: $val:tt),* $(,)? } } => {
$crate::pipeline! { @collect $struct {
bind_groups: [],
vertex_types: [],
fragment_targets: [],
immediate_size: 0,
depth: None,
cull: None,
}; $({$key: $val} )* }
};
{ @texturefmt $inputfmt:ident, ANY } => {
Some($inputfmt)
};
{ @texturefmt $format:ident, $fragmentfmt:ident } => {
if $inputfmt == $fragmentfmt {
Some($inputfmt)
} else {
None
}
};
{ @collect $struct:ident {
bind_groups: $_:tt,
vertex_types: $vertextypes:tt,
fragment_targets: $fragmenttargets:tt,
immediate_size: $immediate:tt,
depth: $depth:tt,
cull: $cull:tt,
}; {bind_groups: $bindgroups:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: $depth,
cull: $cull,
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: $bindgroups:tt,
vertex_types: $_:tt,
fragment_targets: $fragmenttargets:tt,
immediate_size: $immediate:tt,
depth: $depth:tt,
cull: $cull:tt,
}; {vertex_types: $vertextypes:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: $depth,
cull: $cull,
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: $bindgroups:tt,
vertex_types: $vertextypes:tt,
fragment_targets: $_:tt,
immediate_size: $immediate:tt,
depth: $depth:tt,
cull: $cull:tt,
}; {fragment_targets: $fragmenttargets:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: $depth,
cull: $cull,
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: $bindgroups:tt,
vertex_types: $vertextypes:tt,
fragment_targets: $fragmenttargets:tt,
immediate_size: $_:tt,
depth: $depth:tt,
cull: $cull:tt,
}; {immediate_size: $immediate:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: $depth,
cull: $cull,
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: $bindgroups:tt,
vertex_types: $vertextypes:tt,
fragment_targets: $fragmenttargets:tt,
immediate_size: $immediate:tt,
depth: $_:tt,
cull: $cull:tt,
}; {depth: $depth:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: (Some($depth)),
cull: $cull,
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: $bindgroups:tt,
vertex_types: $vertextypes:tt,
fragment_targets: $fragmenttargets:tt,
immediate_size: $immediate:tt,
depth: $depth:tt,
cull: $_:tt,
}; {cull: $cull:tt} $($rest:tt)* } => {
$crate::pipeline! { @collect $struct {
bind_groups: $bindgroups,
vertex_types: $vertextypes,
fragment_targets: $fragmenttargets,
immediate_size: $immediate,
depth: $depth,
cull: (Some($cull)),
}; $($rest)* }
};
{ @collect $struct:ident {
bind_groups: [
$( $bindgroupnum:tt => $bindgroup:ty ),* $(,)?
],
vertex_types: [
$( $vertexnum:tt => $vertexty:ty ),* $(,)?
],
fragment_targets: [
$( $fragmentnum:tt => $blend:ident $mask:ident as $fragmentfmt:ident ),* $(,)?
],
immediate_size: $immediate:expr,
depth: $depth:expr,
cull: $cull:expr,
}; } => {
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct $struct {
pipeline: $crate::wgpu::RenderPipeline,
}
impl ::std::ops::Deref for $struct {
type Target = $crate::wgpu::RenderPipeline;
fn deref(&self) -> &Self::Target {
&self.pipeline
}
}
impl $crate::pipeline::MewPipeline for $struct {
type BindGroupSet = ( $( $bindgroup , )* );
type BindGroupArray<T> = [T; $crate::len! { $( $bindgroupnum )* }];
type VertexArray<T> = [T; $crate::len! { $( $vertexnum )* }];
type FragmentArray<T> = [T; $crate::len! { $( $fragmentnum )* }];
fn new(pipeline: $crate::wgpu::RenderPipeline) -> Self {
Self {
pipeline,
}
}
fn bind_group_layout_types_array() -> Self::BindGroupArray<(::std::any::TypeId, $crate::wgpu::BindGroupLayoutDescriptor<'static>)> {
use $crate::bindgroup::MewBindGroup;
[ $( (
::std::any::TypeId::of::<$bindgroup>(),
<$bindgroup>::layout_desc(),
), )* ]
}
fn map_bind_group_array<'a, A: 'a, B: 'a, F: FnMut(&'a A) -> B>(array: &'a Self::BindGroupArray<A>, f: F) -> Self::BindGroupArray<B> {
array.each_ref().map(f)
}
fn layout_desc<'a>(bind_group_layouts: &'a Self::BindGroupArray<Option<&$crate::wgpu::BindGroupLayout>>) -> $crate::wgpu::PipelineLayoutDescriptor<'a> {
$crate::wgpu::PipelineLayoutDescriptor {
label: Some(concat!(stringify!($struct), " Layout Descriptor")),
bind_group_layouts,
immediate_size: $immediate,
}
}
fn fragment_targets(surface_fmt: $crate::wgpu::TextureFormat) -> Self::FragmentArray<Option<$crate::wgpu::ColorTargetState>> {
[ $( $crate::pipeline! { @texturefmt surface_fmt, $fragmentfmt }.map(|format| $crate::wgpu::ColorTargetState {
format,
blend: Some($crate::wgpu::BlendState::$blend),
write_mask: $crate::wgpu::ColorWrites::$mask,
}), )* ]
}
fn pipeline_desc<'a>(
layout: &'a $crate::pipeline::MewPipelineLayout<Self>,
shader: &'a $crate::wgpu::ShaderModule,
vertex_entry: Option<&'a str>,
fragment_entry: Option<&'a str>,
fragment_targets: &'a Self::FragmentArray<Option<$crate::wgpu::ColorTargetState>>,
) -> $crate::wgpu::RenderPipelineDescriptor<'a> {
#[allow(unused_imports)]
use $crate::wgpu::{
Face::*,
TextureFormat::*,
};
$crate::pipeline::vertices!($struct, $($vertexty),*);
$crate::wgpu::RenderPipelineDescriptor {
label: Some(concat!(stringify!($struct), " Descriptor")),
layout: Some(layout),
vertex: $crate::wgpu::VertexState {
module: shader,
entry_point: vertex_entry,
compilation_options: Default::default(),
buffers: &*VERTICES,
},
fragment: Some($crate::wgpu::FragmentState {
module: shader,
entry_point: fragment_entry,
compilation_options: Default::default(),
targets: fragment_targets,
}),
primitive: $crate::wgpu::PrimitiveState {
topology: $crate::wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: $crate::wgpu::FrontFace::Ccw,
cull_mode: $cull,
polygon_mode: $crate::wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: $depth.map(|format| $crate::wgpu::DepthStencilState {
format,
depth_write_enabled: Some(true),
depth_compare: Some($crate::wgpu::CompareFunction::Less),
stencil: Default::default(),
bias: Default::default(),
}),
multisample: $crate::wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview_mask: None,
cache: None,
}
}
}
};
}
pub use pipeline;
pub trait MewPipeline {
type BindGroupSet;
type BindGroupArray<T>;
type VertexArray<T>;
type FragmentArray<T>;
fn new(pipeline: wgpu::RenderPipeline) -> Self;
fn bind_group_layout_types_array() -> Self::BindGroupArray<(TypeId, wgpu::BindGroupLayoutDescriptor<'static>)>;
fn map_bind_group_array<'a, A: 'a, B: 'a, F: FnMut(&'a A) -> B>(array: &'a Self::BindGroupArray<A>, f: F) -> Self::BindGroupArray<B>;
fn layout_desc<'a>(bind_group_layouts: &'a Self::BindGroupArray<Option<&wgpu::BindGroupLayout>>) -> wgpu::PipelineLayoutDescriptor<'a>;
fn fragment_targets(surface_fmt: wgpu::TextureFormat) -> Self::FragmentArray<Option<wgpu::ColorTargetState>>;
fn pipeline_desc<'a>(
layout: &'a MewPipelineLayout<Self>,
shader: &'a wgpu::ShaderModule,
vertex_entry: Option<&'a str>,
fragment_entry: Option<&'a str>,
fragment_targets: &'a Self::FragmentArray<Option<wgpu::ColorTargetState>>,
) -> wgpu::RenderPipelineDescriptor<'a>;
}
pub struct MewPipelineLayout<PIPE: ?Sized> {
layout: wgpu::PipelineLayout,
_marker: PhantomData<PIPE>,
}
impl<PIPE: ?Sized> Deref for MewPipelineLayout<PIPE> {
type Target = wgpu::PipelineLayout;
fn deref(&self) -> &Self::Target {
&self.layout
}
}
impl<PIPE: ?Sized> MewPipelineLayout<PIPE> {
pub fn new(layout: wgpu::PipelineLayout) -> Self {
Self {
layout,
_marker: PhantomData,
}
}
}