Skip to main content

easy_gpu/assets/render/
pipeline.rs

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) -> Handle<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.fs_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        renderer.asset_manager.render_pipelines.insert(RenderPipeline{
152            pipeline,
153            material_layout,
154        })
155    }
156}
157
158pub fn render_texture(binding: u32) -> wgpu::BindGroupLayoutEntry {
159    wgpu::BindGroupLayoutEntry {
160        binding,
161        visibility: wgpu::ShaderStages::FRAGMENT,
162        ty: wgpu::BindingType::Texture {
163            multisampled: false,
164            view_dimension: wgpu::TextureViewDimension::D2,
165            sample_type: wgpu::TextureSampleType::Float { filterable: true },
166        },
167        count: None,
168    }
169}
170
171pub fn sampler(binding: u32) -> wgpu::BindGroupLayoutEntry {
172    wgpu::BindGroupLayoutEntry {
173        binding,
174        visibility: wgpu::ShaderStages::FRAGMENT,
175        ty: wgpu::BindingType::Sampler(
176            wgpu::SamplerBindingType::Filtering
177        ),
178        count: None,
179    }
180}
181
182pub fn uniform(binding: u32) -> wgpu::BindGroupLayoutEntry {
183    wgpu::BindGroupLayoutEntry {
184        binding,
185        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
186        ty: wgpu::BindingType::Buffer {
187            ty: BufferBindingType::Uniform,
188            has_dynamic_offset: false,
189            min_binding_size: None,
190        },
191        count: None,
192    }
193}