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},
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
115// MARK: Compute pipeline
116
117pub 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
154// MARK: Color pipeline
155
156pub 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
227// MARK: Depth pipeline
228
229pub 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}