1use std::sync::Arc;
2
3use arrayvec::ArrayVec;
4use rend3::{resources::MaterialManager, ModeData, RendererMode};
5use wgpu::{
6 BindGroupLayout, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Device, Face,
7 FragmentState, FrontFace, MultisampleState, PipelineLayoutDescriptor, PolygonMode, PrimitiveState,
8 PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, StencilState, TextureFormat, VertexState,
9};
10
11use crate::{
12 common::{interfaces::ShaderInterfaces, shaders::mode_safe_shader},
13 material::PbrMaterial,
14 vertex::{cpu_vertex_buffers, gpu_vertex_buffers},
15 SampleCount,
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum DepthPassType {
20 Shadow,
21 Prepass,
22}
23
24pub struct BuildDepthPassShaderArgs<'a> {
25 pub mode: RendererMode,
26 pub device: &'a Device,
27
28 pub interfaces: &'a ShaderInterfaces,
29 pub texture_bgl: ModeData<(), &'a BindGroupLayout>,
30
31 pub materials: &'a MaterialManager,
32
33 pub samples: SampleCount,
34 pub ty: DepthPassType,
35}
36
37#[derive(Clone)]
38pub struct DepthPassPipelines {
39 pub cutout: Arc<RenderPipeline>,
40 pub opaque: Arc<RenderPipeline>,
41}
42
43pub fn build_depth_pass_pipeline(args: BuildDepthPassShaderArgs) -> DepthPassPipelines {
44 profiling::scope!("build depth pass pipelines");
45 let depth_vert = unsafe {
46 mode_safe_shader(
47 args.device,
48 args.mode,
49 "depth pass vert",
50 "depth.vert.cpu.spv",
51 "depth.vert.gpu.spv",
52 false,
53 )
54 };
55
56 let depth_opaque_frag = unsafe {
57 mode_safe_shader(
58 args.device,
59 args.mode,
60 "depth pass opaque frag",
61 "depth-opaque.frag.cpu.spv",
62 "depth-opaque.frag.gpu.spv",
63 false,
64 )
65 };
66
67 let depth_cutout_frag = unsafe {
68 mode_safe_shader(
69 args.device,
70 args.mode,
71 "depth pass cutout frag",
72 "depth-cutout.frag.cpu.spv",
73 "depth-cutout.frag.gpu.spv",
74 false,
75 )
76 };
77
78 let mut bgls: ArrayVec<&BindGroupLayout, 4> = ArrayVec::new();
79 bgls.push(&args.interfaces.samplers_bgl);
80 bgls.push(&args.interfaces.culled_object_bgl);
81 bgls.push(args.materials.get_bind_group_layout::<PbrMaterial>());
82 if args.mode == RendererMode::GPUPowered {
83 bgls.push(args.texture_bgl.as_gpu())
84 }
85
86 let pll = args.device.create_pipeline_layout(&PipelineLayoutDescriptor {
87 label: Some("depth prepass"),
88 bind_group_layouts: &bgls,
89 push_constant_ranges: &[],
90 });
91
92 DepthPassPipelines {
93 opaque: Arc::new(create_depth_inner(
94 &args,
95 &pll,
96 &depth_vert,
97 &depth_opaque_frag,
98 match args.ty {
99 DepthPassType::Prepass => "depth opaque prepass",
100 DepthPassType::Shadow => "depth opaque prepass",
101 },
102 )),
103 cutout: Arc::new(create_depth_inner(
104 &args,
105 &pll,
106 &depth_vert,
107 &depth_cutout_frag,
108 match args.ty {
109 DepthPassType::Prepass => "depth cutout prepass",
110 DepthPassType::Shadow => "depth cutout prepass",
111 },
112 )),
113 }
114}
115
116fn create_depth_inner(
117 args: &BuildDepthPassShaderArgs,
118 pll: &wgpu::PipelineLayout,
119 vert: &wgpu::ShaderModule,
120 frag: &wgpu::ShaderModule,
121 name: &str,
122) -> RenderPipeline {
123 profiling::scope!("build depth pipeline", name);
124 let color_state = [ColorTargetState {
125 format: TextureFormat::Rgba16Float,
126 blend: None,
127 write_mask: ColorWrites::empty(),
128 }];
129 let cpu_vertex_buffers = cpu_vertex_buffers();
130 let gpu_vertex_buffers = gpu_vertex_buffers();
131 args.device.create_render_pipeline(&RenderPipelineDescriptor {
132 label: Some(name),
133 layout: Some(pll),
134 vertex: VertexState {
135 module: vert,
136 entry_point: "main",
137 buffers: match args.mode {
138 RendererMode::CPUPowered => &cpu_vertex_buffers,
139 RendererMode::GPUPowered => &gpu_vertex_buffers,
140 },
141 },
142 primitive: PrimitiveState {
143 topology: PrimitiveTopology::TriangleList,
144 strip_index_format: None,
145 front_face: FrontFace::Cw,
146 cull_mode: Some(match args.ty {
147 DepthPassType::Shadow => Face::Front,
148 DepthPassType::Prepass => Face::Back,
149 }),
150 clamp_depth: matches!(args.ty, DepthPassType::Shadow),
151 polygon_mode: PolygonMode::Fill,
152 conservative: false,
153 },
154 depth_stencil: Some(DepthStencilState {
155 format: TextureFormat::Depth32Float,
156 depth_write_enabled: true,
157 depth_compare: match args.ty {
158 DepthPassType::Shadow => CompareFunction::LessEqual,
159 DepthPassType::Prepass => CompareFunction::GreaterEqual,
160 },
161 stencil: StencilState::default(),
162 bias: match args.ty {
163 DepthPassType::Prepass => DepthBiasState::default(),
164 DepthPassType::Shadow => DepthBiasState {
165 constant: 2,
166 slope_scale: 2.0,
167 clamp: 0.0,
168 },
169 },
170 }),
171 multisample: MultisampleState {
172 count: args.samples as u32,
173 ..Default::default()
174 },
175 fragment: Some(FragmentState {
176 module: frag,
177 entry_point: "main",
178 targets: match args.ty {
179 DepthPassType::Prepass => &color_state,
180 DepthPassType::Shadow => &[],
181 },
182 }),
183 })
184}