Skip to main content

ranim_items/vitem/render/
pipeline.rs

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
140// MARK: Compute pipeline
141
142pub 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
179// MARK: Color pipeline
180
181pub 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
252// MARK: Depth pipeline
253
254pub 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}