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
9#[cfg(feature = "selector")]
10use super::{entity_id_pass::EntityIdPass, outline_pass::OutlinePass};
11use super::{line_pipeline::LinePipeline, mesh_pipeline::MeshPipeline, point_pipeline::PointPipeline, upload_pass::PerFrameUniforms};
12
13use crate::forward_renderer::{render_passes::pipeline_runner::PipelineRunner, renderer::OffscreenTarget};
14use easy_wgpu::framebuffer::FrameBuffer;
15
16/// Render all the meshes from the scene
17pub struct MainPass {
18    mesh_pipeline: MeshPipeline,
19    point_pipeline: PointPipeline,
20    line_pipeline: LinePipeline,
21    #[cfg(feature = "selector")]
22    outline_pass: OutlinePass,
23    #[cfg(feature = "selector")]
24    entity_id_pass: EntityIdPass,
25}
26
27impl MainPass {
28    pub fn new(gpu: &Gpu, params: &RenderConfig, color_target_format: wgpu::TextureFormat, depth_target_format: wgpu::TextureFormat) -> Self {
29        let mesh_pipeline = MeshPipeline::new(gpu, params, color_target_format, depth_target_format);
30        let point_pipeline = PointPipeline::new(gpu, params, color_target_format, depth_target_format);
31        let line_pipeline = LinePipeline::new(gpu, params, color_target_format, depth_target_format);
32        #[cfg(feature = "selector")]
33        let outline_pass = OutlinePass::new(gpu, params, color_target_format, depth_target_format);
34        #[cfg(feature = "selector")]
35        let entity_id_pass = EntityIdPass::new(gpu);
36        Self {
37            mesh_pipeline,
38            point_pipeline,
39            line_pipeline,
40            #[cfg(feature = "selector")]
41            outline_pass,
42            #[cfg(feature = "selector")]
43            entity_id_pass,
44        }
45    }
46
47    /// # Panics
48    /// Will panic if the gbuffer does not have the correct textures that are
49    /// needed for the render pass
50    #[allow(clippy::too_many_lines)]
51    pub fn run(
52        &mut self,
53        gpu: &Gpu,
54        per_frame_uniforms: &PerFrameUniforms,
55        offscreen_fb: &FrameBuffer<OffscreenTarget>,
56        out_view: &wgpu::TextureView,
57        scene: &mut Scene,
58        render_params: &RenderConfig,
59    ) {
60        self.begin_pass();
61
62        //tonemap bg color
63        let aces = gloss_utils::tonemap::AcesFitted::new();
64        let bg_color_vec = render_params.bg_color.fixed_rows::<3>(0).clone_owned();
65        let bg_color_tonemapped = aces.tonemap(&bg_color_vec);
66        let bg_color_tonemapped_gamma = na::Vector3::from_iterator(bg_color_tonemapped.iter().map(|x| x.powf(1.0 / 2.2)));
67
68        //queries have to live as long as the encoder so we put them outside of the
69        // pipelines themselves this is because the encoder needs to have
70        // reference to the vertex atributes and those atributes are only alive as long
71        // as the query is also alive.
72        let mut line_query = self.line_pipeline.prepare(gpu, per_frame_uniforms, scene);
73        let mut mesh_query = self.mesh_pipeline.prepare(gpu, per_frame_uniforms, scene);
74        let mut point_query = self.point_pipeline.prepare(gpu, per_frame_uniforms, scene);
75        #[cfg(feature = "selector")]
76        let mut outline_query = self.outline_pass.prepare(gpu, per_frame_uniforms, scene);
77        #[cfg(feature = "selector")]
78        let mut entity_id_query = self.entity_id_pass.prepare(gpu, per_frame_uniforms, scene);
79        //do the actual rendering now
80        let mut encoder = gpu.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
81            label: Some("MainPass Encoder"),
82        });
83        {
84            //check if the depth of color need clearing
85            let color_clear_op = wgpu::LoadOp::Clear(wgpu::Color {
86                r: f64::from(bg_color_tonemapped_gamma.x),
87                g: f64::from(bg_color_tonemapped_gamma.y),
88                b: f64::from(bg_color_tonemapped_gamma.z),
89                a: f64::from(render_params.bg_color.w),
90            });
91
92            let mut selected_out_view = out_view;
93            let mut store = wgpu::StoreOp::Store;
94            let mut resolve_target = None;
95
96            if render_params.msaa_nr_samples > 1 {
97                resolve_target = Some(out_view);
98                selected_out_view = &offscreen_fb.get(OffscreenTarget::MSAAColor).unwrap().view;
99                store = wgpu::StoreOp::Discard; //No need to store the MSAA
100                                                // results, since we never
101                                                // sample from them again, we
102                                                // just use them for resolving
103            }
104            // Main pass - to run the mesh, outline, point and line render passes
105            {
106                let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
107                    label: Some("Main Pass"),
108                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
109                        view: selected_out_view,
110                        resolve_target,
111                        ops: wgpu::Operations { load: color_clear_op, store },
112                    })],
113                    depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
114                        view: &offscreen_fb.get(OffscreenTarget::Depth).unwrap().view,
115                        depth_ops: Some(wgpu::Operations {
116                            load: wgpu::LoadOp::Clear(0.0),
117                            store,
118                        }),
119                        stencil_ops: Some(wgpu::Operations {
120                            load: wgpu::LoadOp::Clear(0),
121                            store: wgpu::StoreOp::Store,
122                        }),
123                    }),
124                    timestamp_writes: None,
125                    occlusion_query_set: None,
126                });
127                self.mesh_pipeline
128                    .run(&mut render_pass, per_frame_uniforms, render_params, &mut mesh_query, scene);
129                self.point_pipeline
130                    .run(&mut render_pass, per_frame_uniforms, render_params, &mut point_query, scene);
131                self.line_pipeline
132                    .run(&mut render_pass, per_frame_uniforms, render_params, &mut line_query, scene);
133                // Run outline pass last so that its able to draw over the line and point passes (grid floor draws over outline otherwise)
134                #[cfg(feature = "selector")]
135                self.outline_pass
136                    .run(&mut render_pass, per_frame_uniforms, render_params, &mut outline_query, scene);
137            }
138
139            // Run entity id pass if a click happened
140            #[cfg(feature = "selector")]
141            if let Some(camera) = scene.get_current_cam() {
142                if camera.is_click(scene) {
143                    let mut entity_id_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
144                        label: Some("Entity ID Pass"),
145                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
146                            view: &offscreen_fb.get(OffscreenTarget::EntityID).unwrap().view,
147                            resolve_target: None,
148                            ops: wgpu::Operations {
149                                load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
150                                store: wgpu::StoreOp::Store,
151                            },
152                        })],
153                        depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
154                            view: &offscreen_fb.get(OffscreenTarget::SingleDepth).unwrap().view,
155                            depth_ops: Some(wgpu::Operations {
156                                load: wgpu::LoadOp::Clear(0.0),
157                                store: wgpu::StoreOp::Discard,
158                            }),
159                            stencil_ops: Some(wgpu::Operations {
160                                load: wgpu::LoadOp::Load,
161                                store: wgpu::StoreOp::Discard,
162                            }),
163                        }),
164                        timestamp_writes: None,
165                        occlusion_query_set: None,
166                    });
167                    self.entity_id_pass
168                        .run(&mut entity_id_pass, per_frame_uniforms, render_params, &mut entity_id_query, scene);
169                }
170            }
171        }
172        gpu.queue().submit(Some(encoder.finish()));
173
174        self.end_pass();
175    }
176
177    fn begin_pass(&mut self) {
178        trace!("begin main_pass");
179    }
180
181    fn end_pass(&mut self) {
182        trace!("end main_pass");
183    }
184}