1use wgpu::{BlendState, BufferBindingType};
2use wgpu::ShaderModule;
3use crate::assets::vertex_layout::BufferLayout;
4use crate::assets_manager::handle::Handle;
5use crate::Renderer;
6
7pub struct RenderPipeline {
8 pub pipeline: wgpu::RenderPipeline,
9 pub material_layout: wgpu::BindGroupLayout,
10}
11
12pub struct RenderPipelineBuilder<'a> {
13 shader: Handle<ShaderModule>,
14 vertex_layouts: Vec<wgpu::VertexBufferLayout<'a>>,
15 pub(crate) depth_format: Option<wgpu::TextureFormat>,
16 depth_writes_enabled: bool,
17 material_entries: Vec<wgpu::BindGroupLayoutEntry>,
18 blend: BlendState,
19 vs_entry: &'a str,
20 fs_entry: &'a str,
21}
22
23impl<'a> RenderPipelineBuilder<'a> {
24 pub fn new(
25 shader: Handle<ShaderModule>,
26 ) -> Self {
27 Self {
28 shader,
29 vertex_layouts: Vec::new(),
30 depth_format: None,
31 depth_writes_enabled: true,
32 material_entries: vec![],
33 blend: BlendState::ALPHA_BLENDING,
34 vs_entry: "vs_main",
35 fs_entry: "fs_main",
36 }
37 }
38 pub fn material_layout(
39 mut self,
40 entries: &[wgpu::BindGroupLayoutEntry],
41 ) -> Self {
42 self.material_entries = entries.to_vec();
43 self
44 }
45
46 pub fn vertex_layout(mut self, layout: BufferLayout) -> Self {
47 self.vertex_layouts.push(layout.to_wgpu_layout());
48 self
49 }
50
51 pub fn depth_format(mut self, format: wgpu::TextureFormat) -> Self {
52 self.depth_format = Some(format);
53 self
54 }
55
56 pub fn depth_writes_enabled(mut self, enabled: bool) -> Self {
57 self.depth_writes_enabled = enabled;
58 self
59 }
60
61 pub fn vs_entry_point(mut self, entry: &'a str) -> Self{
62 self.vs_entry = entry;
63 self
64 }
65
66 pub fn fs_entry_point(mut self, entry: &'a str) -> Self{
67 self.fs_entry = entry;
68 self
69 }
70
71 pub fn additive_alpha_blending(mut self) -> Self{
72 self.blend = wgpu::BlendState {
73 color:wgpu::BlendComponent {
74 src_factor: wgpu::BlendFactor::SrcAlpha,
75 dst_factor: wgpu::BlendFactor::One,
76 operation: wgpu::BlendOperation::Add,
77 },
78 alpha: wgpu::BlendComponent {
79 src_factor: wgpu::BlendFactor::One,
80 dst_factor: wgpu::BlendFactor::One,
81 operation: wgpu::BlendOperation::Add,
82 }};
83 self
84 }
85
86 pub fn blend_mode(mut self,blend_state: BlendState) -> Self{
87 self.blend = blend_state;
88 self
89 }
90
91 pub fn build(self,renderer: &mut Renderer) -> RenderPipeline {
92 if self.depth_format.is_some() && renderer.depth_texture.is_none() {
93 renderer.create_depth_texture(renderer.surface_config.width,renderer.surface_config.height);
94 }
95
96 let shader = renderer.asset_manager.shaders.get(self.shader).unwrap();
97
98 let material_layout = renderer.device.create_bind_group_layout(
99 &wgpu::BindGroupLayoutDescriptor {
100 label: Some("material layout"),
101 entries: &self.material_entries,
102 }
103 );
104
105 let pipeline_layout = renderer.device.create_pipeline_layout(
106 &wgpu::PipelineLayoutDescriptor {
107 label: Some("pipeline layout"),
108 bind_group_layouts: &[
109 Some(&material_layout),
110 ],
111 immediate_size: 0,
112 }
113 );
114
115 let pipeline = renderer.device.create_render_pipeline(
116 &wgpu::RenderPipelineDescriptor {
117 label: Some("pipeline"),
118 layout: Some(&pipeline_layout),
119 vertex: wgpu::VertexState {
120 module: shader,
121 entry_point: Option::from(self.vs_entry),
122 compilation_options: Default::default(),
123 buffers: &self.vertex_layouts,
124 },
125 fragment: Some(wgpu::FragmentState {
126 module: shader,
127 entry_point: Option::from(self.vs_entry),
128 compilation_options: Default::default(),
129 targets: &[Some(wgpu::ColorTargetState {
130 format: renderer.surface_config.format,
131 blend: Some(self.blend),
132 write_mask: wgpu::ColorWrites::ALL,
133 })],
134 }),
135 multiview_mask: None,
136 primitive: wgpu::PrimitiveState::default(),
137 depth_stencil: self.depth_format.map(|format| {
138 wgpu::DepthStencilState {
139 format,
140 depth_write_enabled: Option::from(self.depth_writes_enabled),
141 depth_compare: Option::from(wgpu::CompareFunction::LessEqual),
142 stencil: Default::default(),
143 bias: Default::default(),
144 }
145 }),
146 multisample: wgpu::MultisampleState::default(),
147 cache: None,
148 }
149 );
150
151 RenderPipeline { pipeline, material_layout }
152 }
153}
154
155pub fn texture(binding: u32) -> wgpu::BindGroupLayoutEntry {
156 wgpu::BindGroupLayoutEntry {
157 binding,
158 visibility: wgpu::ShaderStages::FRAGMENT,
159 ty: wgpu::BindingType::Texture {
160 multisampled: false,
161 view_dimension: wgpu::TextureViewDimension::D2,
162 sample_type: wgpu::TextureSampleType::Float { filterable: true },
163 },
164 count: None,
165 }
166}
167
168pub fn sampler(binding: u32) -> wgpu::BindGroupLayoutEntry {
169 wgpu::BindGroupLayoutEntry {
170 binding,
171 visibility: wgpu::ShaderStages::FRAGMENT,
172 ty: wgpu::BindingType::Sampler(
173 wgpu::SamplerBindingType::Filtering
174 ),
175 count: None,
176 }
177}
178
179pub fn uniform(binding: u32) -> wgpu::BindGroupLayoutEntry {
180 wgpu::BindGroupLayoutEntry {
181 binding,
182 visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
183 ty: wgpu::BindingType::Buffer {
184 ty: BufferBindingType::Uniform,
185 has_dynamic_offset: false,
186 min_binding_size: None,
187 },
188 count: None,
189 }
190}