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}