gloss_renderer/forward_renderer/render_passes/
main_pass.rs

1use crate::config::RenderConfig;
2use log::trace;
3use nalgebra as na;
4
5use crate::scene::Scene;
6
7use easy_wgpu::gpu::Gpu;
8
9use super::{line_pipeline::LinePipeline, mesh_pipeline::MeshPipeline, point_pipeline::PointPipeline, upload_pass::PerFrameUniforms};
10
11use crate::forward_renderer::{render_passes::pipeline_runner::PipelineRunner, renderer::OffscreenTarget};
12use easy_wgpu::framebuffer::FrameBuffer;
13
14/// Render all the meshes from the scene
15pub struct MainPass {
16    mesh_pipeline: MeshPipeline,
17    point_pipeline: PointPipeline,
18    line_pipeline: LinePipeline,
19}
20
21impl MainPass {
22    pub fn new(gpu: &Gpu, params: &RenderConfig, color_target_format: wgpu::TextureFormat, depth_target_format: wgpu::TextureFormat) -> Self {
23        let mesh_pipeline = MeshPipeline::new(gpu, params, color_target_format, depth_target_format);
24        let point_pipeline = PointPipeline::new(gpu, params, color_target_format, depth_target_format);
25        let line_pipeline = LinePipeline::new(gpu, params, color_target_format, depth_target_format);
26        Self {
27            mesh_pipeline,
28            point_pipeline,
29            line_pipeline,
30        }
31    }
32
33    /// # Panics
34    /// Will panic if the gbuffer does not have the correct textures that are
35    /// needed for the render pass
36    #[allow(clippy::too_many_lines)]
37    pub fn run(
38        &mut self,
39        gpu: &Gpu,
40        per_frame_uniforms: &PerFrameUniforms,
41        offscreen_fb: &FrameBuffer<OffscreenTarget>,
42        out_view: &wgpu::TextureView,
43        scene: &mut Scene,
44        render_params: &RenderConfig,
45    ) {
46        self.begin_pass();
47
48        //tonemap bg color
49        let aces = gloss_utils::tonemap::AcesFitted::new();
50        let bg_color_vec = render_params.bg_color.fixed_rows::<3>(0).clone_owned();
51        let bg_color_tonemapped = aces.tonemap(&bg_color_vec);
52        let bg_color_tonemapped_gamma = na::Vector3::from_iterator(bg_color_tonemapped.iter().map(|x| x.powf(1.0 / 2.2)));
53
54        //queries have to live as long as the encoder so we put them outside of the
55        // pipelines themselves this is because the encoder needs to have
56        // reference to the vertex atributes and those atributes are only alive as long
57        // as the query is also alive.
58        let mut line_query = self.line_pipeline.prepare(gpu, per_frame_uniforms, scene);
59        let mut mesh_query = self.mesh_pipeline.prepare(gpu, per_frame_uniforms, scene);
60        let mut point_query = self.point_pipeline.prepare(gpu, per_frame_uniforms, scene);
61
62        //do the actual rendering now
63        let mut encoder = gpu.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
64            label: Some("MainPass Encoder"),
65        });
66        {
67            //check if the depth of color need clearing
68            let color_clear_op = wgpu::LoadOp::Clear(wgpu::Color {
69                r: f64::from(bg_color_tonemapped_gamma.x),
70                g: f64::from(bg_color_tonemapped_gamma.y),
71                b: f64::from(bg_color_tonemapped_gamma.z),
72                a: f64::from(render_params.bg_color.w),
73            });
74
75            let mut selected_out_view = out_view;
76            let mut store = wgpu::StoreOp::Store;
77            let mut resolve_target = None;
78
79            if render_params.msaa_nr_samples > 1 {
80                resolve_target = Some(out_view);
81                selected_out_view = &offscreen_fb.get(OffscreenTarget::MSAAColor).unwrap().view;
82                store = wgpu::StoreOp::Discard; //No need to store the MSAA
83                                                // results, since we never
84                                                // sample from them again, we
85                                                // just use them for resolving
86            }
87
88            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
89                label: Some("Main Pass"),
90                color_attachments: &[
91                    //final
92                    Some(wgpu::RenderPassColorAttachment {
93                        view: selected_out_view,
94                        resolve_target,
95                        ops: wgpu::Operations { load: color_clear_op, store },
96                    }),
97                ],
98                depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
99                    view: &offscreen_fb.get(OffscreenTarget::Depth).unwrap().view,
100                    depth_ops: Some(wgpu::Operations {
101                        load: wgpu::LoadOp::Clear(0.0),
102                        store,
103                    }),
104                    stencil_ops: None,
105                }),
106                timestamp_writes: None,
107                occlusion_query_set: None,
108            });
109
110            //Use the piplines to render to the render targets we specified
111            self.mesh_pipeline
112                .run(&mut render_pass, per_frame_uniforms, render_params, &mut mesh_query);
113
114            self.point_pipeline
115                .run(&mut render_pass, per_frame_uniforms, render_params, &mut point_query);
116            self.line_pipeline
117                .run(&mut render_pass, per_frame_uniforms, render_params, &mut line_query);
118        }
119        gpu.queue().submit(Some(encoder.finish()));
120
121        self.end_pass();
122    }
123
124    fn begin_pass(&mut self) {
125        trace!("begin main_pass");
126    }
127
128    fn end_pass(&mut self) {
129        trace!("end main_pass");
130    }
131}