rend3_pbr/
forward.rs

1use std::sync::Arc;
2
3use rend3::{
4    format_sso,
5    resources::{CameraManager, MaterialManager, MeshBuffers, ObjectManager},
6    ModeData,
7};
8use wgpu::{BindGroup, CommandEncoder, Device, RenderPass, RenderPipeline};
9use wgpu_profiler::GpuProfiler;
10
11use crate::{
12    common::{interfaces::ShaderInterfaces, samplers::Samplers},
13    culling::{
14        cpu::{CpuCuller, CpuCullerCullArgs},
15        gpu::{GpuCuller, GpuCullerCullArgs, PreCulledBuffer},
16        CulledObjectSet, Sorting,
17    },
18    material::{PbrMaterial, TransparencyType},
19};
20
21use super::culling;
22
23pub struct ForwardPassCullArgs<'a> {
24    pub device: &'a Device,
25    pub profiler: &'a mut GpuProfiler,
26    pub encoder: &'a mut CommandEncoder,
27
28    pub culler: ModeData<&'a CpuCuller, &'a GpuCuller>,
29
30    pub interfaces: &'a ShaderInterfaces,
31
32    pub camera: &'a CameraManager,
33    pub objects: &'a mut ObjectManager,
34
35    pub culling_input: ModeData<(), &'a mut PreCulledBuffer>,
36}
37
38pub struct ForwardPassPrepassArgs<'rpass, 'b> {
39    pub device: &'b Device,
40    pub profiler: &'b mut GpuProfiler,
41    pub rpass: &'b mut RenderPass<'rpass>,
42
43    pub materials: &'rpass MaterialManager,
44    pub meshes: &'rpass MeshBuffers,
45
46    pub samplers: &'rpass Samplers,
47    pub texture_bg: ModeData<(), &'rpass BindGroup>,
48
49    pub culled_objects: &'rpass CulledObjectSet,
50}
51
52pub struct ForwardPassDrawArgs<'rpass, 'b> {
53    pub device: &'b Device,
54    pub profiler: &'b mut GpuProfiler,
55    pub rpass: &'b mut RenderPass<'rpass>,
56
57    pub materials: &'rpass MaterialManager,
58    pub meshes: &'rpass MeshBuffers,
59
60    pub samplers: &'rpass Samplers,
61    pub directional_light_bg: &'rpass BindGroup,
62    pub texture_bg: ModeData<(), &'rpass BindGroup>,
63    pub shader_uniform_bg: &'rpass BindGroup,
64
65    pub culled_objects: &'rpass CulledObjectSet,
66}
67
68pub struct ForwardPass {
69    depth_pipeline: Option<Arc<RenderPipeline>>,
70    forward_pipeline: Arc<RenderPipeline>,
71    transparency: TransparencyType,
72}
73
74impl ForwardPass {
75    pub fn new(
76        depth_pipeline: Option<Arc<RenderPipeline>>,
77        forward_pipeline: Arc<RenderPipeline>,
78        transparency: TransparencyType,
79    ) -> Self {
80        Self {
81            depth_pipeline,
82            forward_pipeline,
83            transparency,
84        }
85    }
86
87    pub fn cull(&self, args: ForwardPassCullArgs<'_>) -> CulledObjectSet {
88        let label = format_sso!("forward cull {}", self.transparency.to_debug_str());
89        profiling::scope!(&label);
90
91        let sort = if self.transparency == TransparencyType::Blend {
92            Some(Sorting::BackToFront)
93        } else {
94            None
95        };
96
97        match args.culler {
98            ModeData::CPU(cpu_culler) => cpu_culler.cull(CpuCullerCullArgs {
99                device: args.device,
100                camera: args.camera,
101                interfaces: args.interfaces,
102                objects: args.objects,
103                transparency: self.transparency,
104                sort,
105            }),
106            ModeData::GPU(gpu_culler) => {
107                args.profiler.begin_scope(&label, args.encoder, args.device);
108                let culled = gpu_culler.cull(GpuCullerCullArgs {
109                    device: args.device,
110                    encoder: args.encoder,
111                    interfaces: args.interfaces,
112                    camera: args.camera,
113                    input_buffer: args.culling_input.as_gpu(),
114                    sort,
115                });
116                args.profiler.end_scope(args.encoder);
117                culled
118            }
119        }
120    }
121
122    pub fn prepass<'rpass>(&'rpass self, args: ForwardPassPrepassArgs<'rpass, '_>) {
123        let label = self.transparency.to_debug_str();
124        profiling::scope!(label);
125        args.profiler.begin_scope(label, args.rpass, args.device);
126
127        args.meshes.bind(args.rpass);
128
129        args.rpass.set_pipeline(
130            self.depth_pipeline
131                .as_ref()
132                .expect("prepass called on a forward pass with no depth pipeline"),
133        );
134        args.rpass.set_bind_group(0, &args.samplers.linear_nearest_bg, &[]);
135        args.rpass.set_bind_group(1, &args.culled_objects.output_bg, &[]);
136
137        match args.culled_objects.calls {
138            ModeData::CPU(ref draws) => culling::cpu::run(args.rpass, draws, args.samplers, 0, args.materials, 2),
139            ModeData::GPU(ref data) => {
140                args.rpass
141                    .set_bind_group(2, args.materials.get_bind_group_gpu::<PbrMaterial>(), &[]);
142                args.rpass.set_bind_group(3, args.texture_bg.as_gpu(), &[]);
143                culling::gpu::run(args.rpass, data);
144            }
145        }
146        args.profiler.end_scope(args.rpass);
147    }
148
149    pub fn draw<'rpass>(&'rpass self, args: ForwardPassDrawArgs<'rpass, '_>) {
150        let label = self.transparency.to_debug_str();
151        profiling::scope!(label);
152        args.profiler.begin_scope(label, args.rpass, args.device);
153
154        args.meshes.bind(args.rpass);
155
156        args.rpass.set_pipeline(&self.forward_pipeline);
157        args.rpass.set_bind_group(0, &args.samplers.linear_nearest_bg, &[]);
158        args.rpass.set_bind_group(1, &args.culled_objects.output_bg, &[]);
159        args.rpass.set_bind_group(2, args.directional_light_bg, &[]);
160        args.rpass.set_bind_group(3, args.shader_uniform_bg, &[]);
161
162        match args.culled_objects.calls {
163            ModeData::CPU(ref draws) => culling::cpu::run(args.rpass, draws, args.samplers, 0, args.materials, 4),
164            ModeData::GPU(ref data) => {
165                args.rpass
166                    .set_bind_group(4, args.materials.get_bind_group_gpu::<PbrMaterial>(), &[]);
167                args.rpass.set_bind_group(5, args.texture_bg.as_gpu(), &[]);
168                culling::gpu::run(args.rpass, data);
169            }
170        }
171
172        args.profiler.end_scope(args.rpass);
173    }
174}