Skip to main content

ranim_render/pipelines/
vitem.rs

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
126// MARK: Compute pipeline
127
128pub 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
165// MARK: Color pipeline
166
167pub 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
238// MARK: Depth pipeline
239
240pub 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}