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