gloss_renderer/forward_renderer/
renderer.rs1use crate::{
2 components::ConfigChanges,
3 config::{Config, RenderConfig},
4};
5
6use crate::forward_renderer::render_passes::{prepass::PrePass, shadow_pass::ShadowPass, upload_pass::UploadPass};
7
8use crate::{camera::Camera, scene::Scene};
9
10use easy_wgpu::{
11 framebuffer::{FrameBuffer, FrameBufferBuilder},
12 gpu::Gpu,
13 texture::{TexParams, Texture},
14};
15
16use enum_map::Enum;
17use log::debug;
18
19use super::main_pass::MainPass;
20
21#[derive(Debug, Enum)]
22pub enum OffscreenTarget {
23 Color, MSAAColor, Depth,
27}
28
29pub struct RenderData {
32 pub framebuffer: FrameBuffer<OffscreenTarget>,
33}
34impl RenderData {
35 pub fn new(gpu: &Gpu, params: &RenderConfig, surface_format: Option<wgpu::TextureFormat>) -> Self {
36 let frambuffer_builder = FrameBufferBuilder::<OffscreenTarget>::new(128, 128);
38 let depth_texture_usage = if cfg!(target_arch = "wasm32") {
39 wgpu::TextureUsages::RENDER_ATTACHMENT
40 } else {
41 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC
42 };
44
45 let mut offscreen_color_format = wgpu::TextureFormat::Rgba8Unorm;
46 if params.offscreen_color_float_tex {
47 offscreen_color_format = wgpu::TextureFormat::Rgba32Float;
48 }
49
50 let framebuffer = frambuffer_builder
51 .add_render_target(
52 gpu.device(),
53 OffscreenTarget::Color,
54 surface_format.unwrap_or(offscreen_color_format),
55 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, TexParams::default(),
58 )
59 .add_render_target(
60 gpu.device(),
61 OffscreenTarget::MSAAColor,
62 surface_format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm),
63 wgpu::TextureUsages::RENDER_ATTACHMENT,
64 TexParams {
65 sample_count: params.msaa_nr_samples,
66 ..Default::default()
67 },
68 )
69 .add_render_target(
70 gpu.device(),
71 OffscreenTarget::Depth,
72 wgpu::TextureFormat::Depth32Float,
73 depth_texture_usage,
74 TexParams {
75 sample_count: params.msaa_nr_samples,
76 ..Default::default()
77 },
78 )
79 .build(gpu.device());
80
81 Self { framebuffer }
82 }
83}
84
85pub struct RenderPasses {
86 pub upload_pass: UploadPass, shadow_pass: ShadowPass, main_pass: MainPass,
89}
90impl RenderPasses {
91 pub fn new(gpu: &Gpu, params: &RenderConfig, color_target_format: wgpu::TextureFormat, depth_target_format: wgpu::TextureFormat) -> Self {
92 let upload_pass = UploadPass::new(gpu, params);
93 let shadow_pass = ShadowPass::new(gpu);
94 let main_pass = MainPass::new(gpu, params, color_target_format, depth_target_format);
95 Self {
96 upload_pass,
97 shadow_pass,
98 main_pass,
99 }
100 }
101
102 #[allow(clippy::too_many_arguments)]
103 pub fn run(&mut self, out_view: &wgpu::TextureView, data: &RenderData, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
104 let global_uniforms = self.upload_pass.run(gpu, camera, scene, &config.render);
106
107 self.shadow_pass.run(gpu, global_uniforms, scene);
109
110 self.main_pass
111 .run(gpu, global_uniforms, &data.framebuffer, out_view, scene, &config.render);
112 }
113}
114
115pub struct Renderer {
121 pub data: RenderData,
123 prepass: PrePass,
125 pub passes: RenderPasses,
126}
127
128impl Renderer {
129 pub fn new(gpu: &Gpu, params: &RenderConfig, surface_format: Option<wgpu::TextureFormat>) -> Self {
130 let data = RenderData::new(gpu, params, surface_format);
131
132 let prepass = PrePass::new();
135
136 let color_target_format = data.framebuffer.get(OffscreenTarget::Color).unwrap().texture.format();
139 let depth_target_format = data.framebuffer.get(OffscreenTarget::Depth).unwrap().texture.format();
140
141 let passes = RenderPasses::new(gpu, params, color_target_format, depth_target_format);
142
143 Self { data, prepass, passes }
144 }
145
146 #[allow(clippy::too_many_arguments)]
151 pub fn render_to_view(
152 &mut self,
153 out_view: &wgpu::TextureView,
154 gpu: &Gpu,
157 camera: &mut Camera,
158 scene: &mut Scene,
159 config: &mut Config,
160 _dt: core::time::Duration,
161 ) {
162 self.begin_frame(gpu, camera, scene, config);
163
164 self.passes.run(out_view, &self.data, gpu, camera, scene, config);
165
166 self.end_frame(scene);
167 }
168
169 #[allow(clippy::too_many_arguments)]
178 pub fn render_to_texture(
179 &mut self,
180 gpu: &Gpu,
183 camera: &mut Camera,
184 scene: &mut Scene,
185 config: &mut Config,
186 _dt: core::time::Duration,
187 ) {
188 self.begin_frame(gpu, camera, scene, config);
189
190 let out_view = &self.data.framebuffer.get(OffscreenTarget::Color).unwrap().view;
191 self.passes.run(out_view, &self.data, gpu, camera, scene, config);
192
193 self.end_frame(scene);
194 }
195
196 fn prepare_for_rendering(&mut self, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
197 if let Ok(delta) = scene.get_resource::<&ConfigChanges>() {
199 config.apply_deltas(&delta);
200 }
201
202 self.prepass.run(gpu, camera, scene, config);
204 }
205
206 fn begin_frame(&mut self, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
207 let (width, height) = camera.get_target_res(scene);
209 self.resize_if_necesary(width, height, gpu);
210 self.prepare_for_rendering(gpu, camera, scene, config);
211 }
212
213 fn end_frame(&self, scene: &mut Scene) {
214 scene.world.clear_trackers();
217 }
218
219 pub fn rendered_tex(&self) -> &Texture {
223 self.data.framebuffer.get(OffscreenTarget::Color).unwrap()
224 }
225 pub fn rendered_tex_mut(&mut self) -> &mut Texture {
229 self.data.framebuffer.get_mut(OffscreenTarget::Color).unwrap()
230 }
231 pub fn depth_buffer(&self) -> &Texture {
235 self.data.framebuffer.get(OffscreenTarget::Depth).unwrap()
236 }
237
238 fn resize_if_necesary(&mut self, width: u32, height: u32, gpu: &Gpu) {
239 if self.data.framebuffer.width != width || self.data.framebuffer.height != height {
240 debug!(
241 "resizing framebuffer because it is size {}, {}",
242 self.data.framebuffer.width, self.data.framebuffer.height
243 );
244 self.data.framebuffer.resize(gpu.device(), width, height);
245 }
246 }
247}