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
21pub const ENTITY_ID_PASS_SCALE_FACTOR: u32 = 8;
22
23#[derive(Debug, Enum)]
24pub enum OffscreenTarget {
25 Color, MSAAColor, Depth, EntityID, SingleDepth, }
32
33pub struct RenderData {
36 pub framebuffer: FrameBuffer<OffscreenTarget>,
37}
38impl RenderData {
39 pub fn new(gpu: &Gpu, params: &RenderConfig, surface_format: Option<wgpu::TextureFormat>) -> Self {
40 let frambuffer_builder = FrameBufferBuilder::<OffscreenTarget>::new(128, 128);
42 let depth_texture_usage = if cfg!(target_arch = "wasm32") {
43 wgpu::TextureUsages::RENDER_ATTACHMENT
44 } else {
45 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC
46 };
48
49 let mut offscreen_color_format = wgpu::TextureFormat::Rgba8Unorm;
50 if params.offscreen_color_float_tex {
51 offscreen_color_format = wgpu::TextureFormat::Rgba32Float;
52 }
53
54 let framebuffer = frambuffer_builder
55 .add_render_target(
56 gpu.device(),
57 OffscreenTarget::Color,
58 surface_format.unwrap_or(offscreen_color_format),
59 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, TexParams::default(),
62 )
63 .add_render_target(
64 gpu.device(),
65 OffscreenTarget::MSAAColor,
66 surface_format.unwrap_or(wgpu::TextureFormat::Rgba8Unorm),
67 wgpu::TextureUsages::RENDER_ATTACHMENT,
68 TexParams {
69 sample_count: params.msaa_nr_samples,
70 ..Default::default()
71 },
72 )
73 .add_render_target(
74 gpu.device(),
75 OffscreenTarget::Depth,
76 wgpu::TextureFormat::Depth32FloatStencil8,
77 depth_texture_usage,
78 TexParams {
79 sample_count: params.msaa_nr_samples,
80 ..Default::default()
81 },
82 )
83 .add_render_target(
84 gpu.device(),
85 OffscreenTarget::SingleDepth,
86 wgpu::TextureFormat::Depth16Unorm,
87 depth_texture_usage,
88 TexParams {
89 scale_factor: ENTITY_ID_PASS_SCALE_FACTOR,
90 ..Default::default()
91 },
92 )
93 .add_render_target(
94 gpu.device(),
95 OffscreenTarget::EntityID,
96 wgpu::TextureFormat::Rgba8Unorm,
97 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::COPY_DST,
98 TexParams {
99 scale_factor: ENTITY_ID_PASS_SCALE_FACTOR,
100 ..Default::default()
101 },
102 )
103 .build(gpu.device());
104
105 Self { framebuffer }
106 }
107}
108
109pub struct RenderPasses {
110 pub upload_pass: UploadPass, shadow_pass: ShadowPass, main_pass: MainPass,
113}
114impl RenderPasses {
115 pub fn new(gpu: &Gpu, params: &RenderConfig, color_target_format: wgpu::TextureFormat, depth_target_format: wgpu::TextureFormat) -> Self {
116 let upload_pass = UploadPass::new(gpu, params);
117 let shadow_pass = ShadowPass::new(gpu);
118 let main_pass = MainPass::new(gpu, params, color_target_format, depth_target_format);
119 Self {
120 upload_pass,
121 shadow_pass,
122 main_pass,
123 }
124 }
125
126 #[allow(clippy::too_many_arguments)]
127 pub fn run(&mut self, out_view: &wgpu::TextureView, data: &RenderData, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
128 let global_uniforms = self.upload_pass.run(gpu, camera, scene, &config.render);
130 self.shadow_pass.run(gpu, global_uniforms, scene);
132 self.main_pass
133 .run(gpu, global_uniforms, &data.framebuffer, out_view, scene, &config.render);
134 }
135}
136
137pub struct Renderer {
143 pub data: RenderData,
145 prepass: PrePass,
147 pub passes: RenderPasses,
148}
149
150impl Renderer {
151 pub fn new(gpu: &Gpu, params: &RenderConfig, surface_format: Option<wgpu::TextureFormat>) -> Self {
152 let data = RenderData::new(gpu, params, surface_format);
153
154 let prepass = PrePass::new();
157
158 let color_target_format = data.framebuffer.get(OffscreenTarget::Color).unwrap().texture.format();
161 let depth_target_format = data.framebuffer.get(OffscreenTarget::Depth).unwrap().texture.format();
162
163 let passes = RenderPasses::new(gpu, params, color_target_format, depth_target_format);
164
165 Self { data, prepass, passes }
166 }
167
168 #[allow(clippy::too_many_arguments)]
173 pub fn render_to_view(
174 &mut self,
175 out_view: &wgpu::TextureView,
176 gpu: &Gpu,
179 camera: &mut Camera,
180 scene: &mut Scene,
181 config: &mut Config,
182 _dt: core::time::Duration,
183 ) {
184 self.begin_frame(gpu, camera, scene, config);
185
186 self.passes.run(out_view, &self.data, gpu, camera, scene, config);
187
188 self.end_frame(scene);
189 }
190
191 #[allow(clippy::too_many_arguments)]
200 pub fn render_to_texture(
201 &mut self,
202 gpu: &Gpu,
205 camera: &mut Camera,
206 scene: &mut Scene,
207 config: &mut Config,
208 _dt: core::time::Duration,
209 ) {
210 self.begin_frame(gpu, camera, scene, config);
211
212 let out_view = &self.data.framebuffer.get(OffscreenTarget::Color).unwrap().view;
213 self.passes.run(out_view, &self.data, gpu, camera, scene, config);
214
215 self.end_frame(scene);
216 }
217
218 fn prepare_for_rendering(&mut self, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
219 if let Ok(delta) = scene.get_resource::<&ConfigChanges>() {
221 config.apply_deltas(&delta);
222 }
223
224 self.prepass.run(gpu, camera, scene, config);
226 }
227
228 fn begin_frame(&mut self, gpu: &Gpu, camera: &mut Camera, scene: &mut Scene, config: &mut Config) {
229 let (width, height) = camera.get_target_res(scene);
231 self.resize_if_necesary(width, height, gpu);
232 self.prepare_for_rendering(gpu, camera, scene, config);
233 }
234
235 fn end_frame(&self, scene: &mut Scene) {
236 scene.world.clear_trackers();
239 }
240
241 pub fn rendered_tex(&self) -> &Texture {
245 self.data.framebuffer.get(OffscreenTarget::Color).unwrap()
246 }
247 pub fn rendered_tex_mut(&mut self) -> &mut Texture {
251 self.data.framebuffer.get_mut(OffscreenTarget::Color).unwrap()
252 }
253 pub fn depth_buffer(&self) -> &Texture {
257 self.data.framebuffer.get(OffscreenTarget::Depth).unwrap()
258 }
259
260 pub fn entity_id_buffer(&self) -> &Texture {
261 self.data.framebuffer.get(OffscreenTarget::EntityID).unwrap()
262 }
263
264 fn resize_if_necesary(&mut self, width: u32, height: u32, gpu: &Gpu) {
265 if self.data.framebuffer.width != width || self.data.framebuffer.height != height {
266 debug!(
267 "resizing framebuffer because it is size {}, {}",
268 self.data.framebuffer.width, self.data.framebuffer.height
269 );
270 self.data.framebuffer.resize(gpu.device(), width, height);
271 }
272 }
273}