1use std::{
2 marker::PhantomData,
3 ops::Deref,
4};
5
6
7#[macro_export]
33macro_rules! pipeline {
34 { @len } => {
35 0
36 };
37 { @len $last:tt } => {
38 $last + 1
39 };
40 { @len $first:tt $( $rest:tt )+ } => {
41 $crate::bind_group! { @len $( $rest )+ }
42 };
43
44 { @texturefmt $var:ident , SURFACE } => {
45 $var
46 };
47 { @texturefmt $var:ident , $fragmentfmt:ident } => {
48 Some($crate::wgpu::TextureFormat::$fragmentfmt)
49 };
50
51 { $struct:ident {
52 bind_groups : [
53 $( $bindgroupnum:tt => $bindgroup:ty ),* $(,)?
54 ],
55 vertex_types: [
56 $( $vertexnum:tt => $vertexty:ty ),* $(,)?
57 ],
58 fragment_targets: [
59 $( $fragmentnum:tt => $blend:ident $mask:ident as $fragmentfmt:ident ),* $(,)?
60 ],
61 push_constants: [
62 $( $pushfrom:literal .. $pushto:literal @ $pushshaderstage:ident ),* $(,)?
63 ],
64 depth: $depthfmt:expr,
65 cull: $cull:expr,
66 } } => {
67 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
68 pub struct $struct {
69 pipeline: $crate::wgpu::RenderPipeline,
70 }
71
72 impl ::std::ops::Deref for $struct {
73 type Target = $crate::wgpu::RenderPipeline;
74 fn deref(&self) -> &Self::Target {
75 &self.pipeline
76 }
77 }
78
79 impl $struct {
80 pub fn get_layouts_from_refs<GETTER>(getter: &GETTER) -> <Self as $crate::pipeline::MewPipeline>::BindGroupLayoutSet<'_>
81 where
82 GETTER: $( AsRef<$crate::bindgroup::MewBindGroupLayout<$bindgroup>> + )*
83 {
84 ( $( {
85 let layout: &$crate::bindgroup::MewBindGroupLayout<$bindgroup> = getter.as_ref();
86 layout
87 }, )* )
88 }
89 }
90
91 impl $crate::pipeline::MewPipeline for $struct {
92 type BindGroupSet = ( $( $bindgroup , )* );
93 type BindGroupLayoutSet<'a> = ( $( &'a MewBindGroupLayout<$bindgroup> , )* );
94 type BindGroupArray<T> = [T; $crate::pipeline! { @len $( $bindgroupnum )* }];
95 type VertexArray<T> = [T; $crate::pipeline! { @len $( $vertexnum )* }];
96 type FragmentArray<T> = [T; $crate::pipeline! { @len $( $fragmentnum )* }];
97
98 fn new(pipeline: $crate::wgpu::RenderPipeline) -> Self {
99 Self {
100 pipeline,
101 }
102 }
103
104 fn bind_group_layouts<'a>(bind_group_layouts: &Self::BindGroupLayoutSet<'a>) -> Self::BindGroupArray<&'a $crate::wgpu::BindGroupLayout> {
105 [ $(
106 bind_group_layouts.$bindgroupnum,
107 )* ]
108 }
109
110
111 fn layout_desc<'a>(bind_group_layouts: &'a Self::BindGroupArray<&'a $crate::wgpu::BindGroupLayout>) -> $crate::wgpu::PipelineLayoutDescriptor<'a> {
113 $crate::wgpu::PipelineLayoutDescriptor {
114 label: Some(concat!(stringify!($struct), " Layout Descriptor")),
115 bind_group_layouts,
116 push_constant_ranges: &[ $(
117 $crate::wgpu::PushConstantRange {
118 stages: $crate::wgpu::ShaderStages::$pushshaderstage,
119 range: $pushfrom..$pushto,
120 },
121 )* ],
122 }
123 }
124
125 fn fragment_targets<'a>(surface_fmt: Option<$crate::wgpu::TextureFormat>) -> Self::FragmentArray<Option<$crate::wgpu::ColorTargetState>> {
126 [ $( $crate::pipeline! { @texturefmt surface_fmt, $fragmentfmt }.map(|format| $crate::wgpu::ColorTargetState {
127 format,
128 blend: Some($crate::wgpu::BlendState::$blend),
129 write_mask: $crate::wgpu::ColorWrites::$mask,
130 }), )* ]
131 }
132
133 fn pipeline_desc<'a>(
134 layout: &'a $crate::pipeline::MewPipelineLayout<Self>,
135 shader: &'a $crate::wgpu::ShaderModule,
136 vertex_entry: Option<&'a str>,
137 fragment_entry: Option<&'a str>,
138 fragment_targets: &'a Self::FragmentArray<Option<$crate::wgpu::ColorTargetState>>,
139 ) -> $crate::wgpu::RenderPipelineDescriptor<'a> {
140 use ::std::sync::LazyLock;
141 use $crate::wgpu::{
142 Face::*,
143 TextureFormat::*,
144 };
145
146 static VERTICES: LazyLock<<$struct as $crate::pipeline::MewPipeline>::VertexArray<$crate::wgpu::VertexBufferLayout<'static>>> = LazyLock::new(||
147 [ $( <$vertexty>::vertex_layout(), )* ]
148 );
149
150 $crate::wgpu::RenderPipelineDescriptor {
151 label: Some(concat!(stringify!($struct), " Descriptor")),
152 layout: Some(layout),
153 vertex: $crate::wgpu::VertexState {
154 module: shader,
155 entry_point: vertex_entry,
156 compilation_options: Default::default(),
157 buffers: &*VERTICES,
158 },
159 fragment: Some($crate::wgpu::FragmentState {
160 module: shader,
161 entry_point: fragment_entry,
162 compilation_options: Default::default(),
163 targets: fragment_targets,
164 }),
165 primitive: $crate::wgpu::PrimitiveState {
166 topology: $crate::wgpu::PrimitiveTopology::TriangleList,
167 strip_index_format: None,
168 front_face: $crate::wgpu::FrontFace::Ccw,
169 cull_mode: $cull,
170 polygon_mode: $crate::wgpu::PolygonMode::Fill,
171 unclipped_depth: false,
172 conservative: false,
173 },
174 depth_stencil: $depthfmt.map(|format| $crate::wgpu::DepthStencilState {
175 format,
176 depth_write_enabled: true,
177 depth_compare: $crate::wgpu::CompareFunction::Less,
178 stencil: Default::default(),
179 bias: Default::default(),
180 }),
181 multisample: $crate::wgpu::MultisampleState {
182 count: 1,
183 mask: !0,
184 alpha_to_coverage_enabled: true,
185 },
186 multiview: None,
187 cache: None,
188 }
189 }
190 }
191 };
192}
193pub use pipeline;
194
195
196pub trait MewPipeline {
217 type BindGroupSet;
219 type BindGroupLayoutSet<'a>;
221 type BindGroupArray<T>;
222 type VertexArray<T>;
223 type FragmentArray<T>;
224
225 fn new(pipeline: wgpu::RenderPipeline) -> Self;
227 fn bind_group_layouts<'a>(bind_groups: &Self::BindGroupLayoutSet<'a>) -> Self::BindGroupArray<&'a wgpu::BindGroupLayout>;
230 fn layout_desc<'a>(bind_group_layouts: &'a Self::BindGroupArray<&'a wgpu::BindGroupLayout>) -> wgpu::PipelineLayoutDescriptor<'a>;
234
235 fn fragment_targets<'a>(surface_fmt: Option<wgpu::TextureFormat>) -> Self::FragmentArray<Option<wgpu::ColorTargetState>>;
236
237 fn pipeline_desc<'a>(
238 layout: &'a MewPipelineLayout<Self>,
239 shader: &'a wgpu::ShaderModule,
240 vertex_entry: Option<&'a str>,
241 fragment_entry: Option<&'a str>,
242 fragment_targets: &'a Self::FragmentArray<Option<wgpu::ColorTargetState>>,
243 ) -> wgpu::RenderPipelineDescriptor<'a>;
244}
245
246
247pub struct MewPipelineLayout<PIPE: ?Sized> {
250 layout: wgpu::PipelineLayout,
251 _marker: PhantomData<PIPE>,
252}
253impl<PIPE: ?Sized> Deref for MewPipelineLayout<PIPE> {
254 type Target = wgpu::PipelineLayout;
255 fn deref(&self) -> &Self::Target {
256 &self.layout
257 }
258}
259impl<PIPE: ?Sized> MewPipelineLayout<PIPE> {
260 pub fn new(layout: wgpu::PipelineLayout) -> Self {
262 Self {
263 layout,
264 _marker: PhantomData,
265 }
266 }
267}