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