1use std::ops::Deref;
2
3use bevy_ecs::prelude::*;
4
5use crate::{
6 ResolutionInfo, WgpuContext,
7 primitives::{
8 viewport::{ViewportBindGroup, ViewportGpuPacket},
9 vitems::VItemsBuffer,
10 },
11 resource::{GpuResource, OUTPUT_TEXTURE_FORMAT, PipelinesPool},
12 schedule::{FrameTarget, RenderContext, RenderProfiler},
13};
14
15pub(crate) fn compute(
16 mut render: RenderContext,
17 ctx: Res<WgpuContext>,
18 pipelines: Res<PipelinesPool>,
19 merged: Res<VItemsBuffer>,
20 profiler: Res<RenderProfiler>,
21) {
22 if merged.item_count() == 0 {
23 return;
24 }
25 let mut pass = render
26 .encoder()
27 .begin_compute_pass(&wgpu::ComputePassDescriptor {
28 label: Some("Merged VItem Map Points Compute Pass"),
29 timestamp_writes: None,
30 });
31 profiler.scope_pass("vitem::compute", &mut pass, |pass| {
32 pass.set_pipeline(&pipelines.get_or_init::<VItemComputePipeline>(&ctx));
33 pass.set_bind_group(0, merged.compute_bind_group.as_ref().unwrap(), &[]);
34 pass.dispatch_workgroups(merged.total_points().div_ceil(256), 1, 1);
35 });
36}
37
38#[allow(clippy::too_many_arguments)]
39pub(crate) fn depth(
40 mut render: RenderContext,
41 ctx: Res<WgpuContext>,
42 pipelines: Res<PipelinesPool>,
43 resolution: Res<ResolutionInfo>,
44 target: Res<FrameTarget>,
45 viewport: Res<ViewportGpuPacket>,
46 merged: Res<VItemsBuffer>,
47 profiler: Res<RenderProfiler>,
48) {
49 if merged.item_count() == 0 {
50 return;
51 }
52 let mut pass = render
53 .encoder()
54 .begin_render_pass(&wgpu::RenderPassDescriptor {
55 label: Some("Merged VItem Depth Render Pass"),
56 color_attachments: &[],
57 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
58 view: &target.depth_stencil_view,
59 depth_ops: Some(wgpu::Operations {
60 load: wgpu::LoadOp::Load,
61 store: wgpu::StoreOp::Store,
62 }),
63 stencil_ops: None,
64 }),
65 timestamp_writes: None,
66 occlusion_query_set: None,
67 multiview_mask: None,
68 });
69 profiler.scope_pass("vitem::depth", &mut pass, |pass| {
70 pass.set_pipeline(&pipelines.get_or_init::<VItemDepthPipeline>(&ctx));
71 pass.set_bind_group(0, &resolution.bind_group, &[]);
72 pass.set_bind_group(1, &viewport.uniforms_bind_group.bind_group, &[]);
73 pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
74 pass.draw(0..4, 0..merged.item_count());
75 });
76}
77
78#[allow(clippy::too_many_arguments)]
79pub(crate) fn color(
80 mut render: RenderContext,
81 ctx: Res<WgpuContext>,
82 pipelines: Res<PipelinesPool>,
83 resolution: Res<ResolutionInfo>,
84 target: Res<FrameTarget>,
85 viewport: Res<ViewportGpuPacket>,
86 merged: Res<VItemsBuffer>,
87 profiler: Res<RenderProfiler>,
88) {
89 if merged.item_count() == 0 {
90 return;
91 }
92 let mut pass = render
93 .encoder()
94 .begin_render_pass(&wgpu::RenderPassDescriptor {
95 label: Some("Merged VItem Color Render Pass"),
96 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
97 view: &target.render_view,
98 resolve_target: None,
99 depth_slice: None,
100 ops: wgpu::Operations {
101 load: wgpu::LoadOp::Load,
102 store: wgpu::StoreOp::Store,
103 },
104 })],
105 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
106 view: &target.depth_stencil_view,
107 depth_ops: Some(wgpu::Operations {
108 load: wgpu::LoadOp::Load,
109 store: wgpu::StoreOp::Store,
110 }),
111 stencil_ops: None,
112 }),
113 timestamp_writes: None,
114 occlusion_query_set: None,
115 multiview_mask: None,
116 });
117 profiler.scope_pass("vitem::color", &mut pass, |pass| {
118 pass.set_pipeline(&pipelines.get_or_init::<VItemColorPipeline>(&ctx));
119 pass.set_bind_group(0, &resolution.bind_group, &[]);
120 pass.set_bind_group(1, &viewport.uniforms_bind_group.bind_group, &[]);
121 pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
122 pass.draw(0..4, 0..merged.item_count());
123 });
124}
125
126pub struct VItemComputePipeline {
129 pipeline: wgpu::ComputePipeline,
130}
131
132impl Deref for VItemComputePipeline {
133 type Target = wgpu::ComputePipeline;
134 fn deref(&self) -> &Self::Target {
135 &self.pipeline
136 }
137}
138
139impl GpuResource for VItemComputePipeline {
140 fn new(ctx: &WgpuContext) -> Self {
141 let module = &ctx
142 .device
143 .create_shader_module(wgpu::include_wgsl!("./shaders/vitem_compute.wgsl"));
144 let layout = ctx
145 .device
146 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
147 label: Some("VItem Compute Pipeline Layout"),
148 bind_group_layouts: &[Some(&VItemsBuffer::compute_bind_group_layout(ctx))],
149 immediate_size: 0,
150 });
151 let pipeline = ctx
152 .device
153 .create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
154 label: Some("VItem Compute Pipeline"),
155 layout: Some(&layout),
156 module,
157 entry_point: Some("cs_main"),
158 compilation_options: wgpu::PipelineCompilationOptions::default(),
159 cache: None,
160 });
161 Self { pipeline }
162 }
163}
164
165pub struct VItemColorPipeline {
168 pipeline: wgpu::RenderPipeline,
169}
170
171impl Deref for VItemColorPipeline {
172 type Target = wgpu::RenderPipeline;
173 fn deref(&self) -> &Self::Target {
174 &self.pipeline
175 }
176}
177
178impl GpuResource for VItemColorPipeline {
179 fn new(ctx: &WgpuContext) -> Self {
180 let module = &ctx
181 .device
182 .create_shader_module(wgpu::include_wgsl!("./shaders/vitem.wgsl"));
183 let layout = ctx
184 .device
185 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
186 label: Some("VItem Color Pipeline Layout"),
187 bind_group_layouts: &[
188 Some(&ResolutionInfo::create_bind_group_layout(ctx)),
189 Some(&ViewportBindGroup::bind_group_layout(ctx)),
190 Some(&VItemsBuffer::render_bind_group_layout(ctx)),
191 ],
192 immediate_size: 0,
193 });
194 let pipeline = ctx
195 .device
196 .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
197 label: Some("VItem Color Pipeline"),
198 layout: Some(&layout),
199 vertex: wgpu::VertexState {
200 module,
201 entry_point: Some("vs_main"),
202 buffers: &[],
203 compilation_options: wgpu::PipelineCompilationOptions::default(),
204 },
205 fragment: Some(wgpu::FragmentState {
206 module,
207 entry_point: Some("fs_main"),
208 compilation_options: wgpu::PipelineCompilationOptions::default(),
209 targets: &[Some(wgpu::ColorTargetState {
210 format: OUTPUT_TEXTURE_FORMAT,
211 blend: Some(wgpu::BlendState::ALPHA_BLENDING),
212 write_mask: wgpu::ColorWrites::ALL,
213 })],
214 }),
215 primitive: wgpu::PrimitiveState {
216 topology: wgpu::PrimitiveTopology::TriangleStrip,
217 ..Default::default()
218 },
219 depth_stencil: Some(wgpu::DepthStencilState {
220 format: wgpu::TextureFormat::Depth32Float,
221 depth_write_enabled: Some(false),
222 depth_compare: Some(wgpu::CompareFunction::LessEqual),
223 stencil: wgpu::StencilState::default(),
224 bias: wgpu::DepthBiasState::default(),
225 }),
226 multisample: wgpu::MultisampleState {
227 count: 1,
228 mask: !0,
229 alpha_to_coverage_enabled: false,
230 },
231 multiview_mask: None,
232 cache: None,
233 });
234 Self { pipeline }
235 }
236}
237
238pub struct VItemDepthPipeline {
241 pipeline: wgpu::RenderPipeline,
242}
243
244impl Deref for VItemDepthPipeline {
245 type Target = wgpu::RenderPipeline;
246 fn deref(&self) -> &Self::Target {
247 &self.pipeline
248 }
249}
250
251impl GpuResource for VItemDepthPipeline {
252 fn new(ctx: &WgpuContext) -> Self {
253 let module = &ctx
254 .device
255 .create_shader_module(wgpu::include_wgsl!("./shaders/vitem.wgsl"));
256 let layout = ctx
257 .device
258 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
259 label: Some("VItem Depth Pipeline Layout"),
260 bind_group_layouts: &[
261 Some(&ResolutionInfo::create_bind_group_layout(ctx)),
262 Some(&ViewportBindGroup::bind_group_layout(ctx)),
263 Some(&VItemsBuffer::render_bind_group_layout(ctx)),
264 ],
265 immediate_size: 0,
266 });
267 let pipeline = ctx
268 .device
269 .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
270 label: Some("VItem Depth Pipeline"),
271 layout: Some(&layout),
272 vertex: wgpu::VertexState {
273 module,
274 entry_point: Some("vs_main"),
275 buffers: &[],
276 compilation_options: wgpu::PipelineCompilationOptions::default(),
277 },
278 fragment: Some(wgpu::FragmentState {
279 module,
280 entry_point: Some("fs_depth_only"),
281 compilation_options: wgpu::PipelineCompilationOptions::default(),
282 targets: &[],
283 }),
284 primitive: wgpu::PrimitiveState {
285 topology: wgpu::PrimitiveTopology::TriangleStrip,
286 ..Default::default()
287 },
288 depth_stencil: Some(wgpu::DepthStencilState {
289 format: wgpu::TextureFormat::Depth32Float,
290 depth_write_enabled: Some(true),
291 depth_compare: Some(wgpu::CompareFunction::Less),
292 stencil: wgpu::StencilState::default(),
293 bias: wgpu::DepthBiasState::default(),
294 }),
295 multisample: wgpu::MultisampleState {
296 count: 1,
297 mask: !0,
298 alpha_to_coverage_enabled: false,
299 },
300 multiview_mask: None,
301 cache: None,
302 });
303 Self { pipeline }
304 }
305}