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