Skip to main content

ranim_items/mesh/render/
pipeline.rs

1use std::ops::Deref;
2
3use bevy_ecs::prelude::*;
4
5use super::{RenderMeshItem, buffer::MeshItemsBuffer};
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_mesh_items(
16    ctx: Res<WgpuContext>,
17    mut buffer: ResMut<MeshItemsBuffer>,
18    items: Query<(&SceneOrder, &RenderMeshItem)>,
19) {
20    let _span = ranim_render::cpu_probe::span("prepare_mesh_items");
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
29#[allow(clippy::too_many_arguments)]
30pub(crate) fn depth(
31    mut render: RenderContext,
32    ctx: Res<WgpuContext>,
33    pipelines: Res<PipelinesPool>,
34    resolution: Res<ResolutionInfo>,
35    target: Res<FrameTarget>,
36    viewport: Res<ViewportGpuPacket>,
37    merged: Res<MeshItemsBuffer>,
38    profiler: Res<RenderProfiler>,
39) {
40    if merged.item_count() == 0 {
41        return;
42    }
43    let mut pass = render
44        .encoder()
45        .begin_render_pass(&wgpu::RenderPassDescriptor {
46            label: Some("Merged RenderMeshItem Depth Render Pass"),
47            color_attachments: &[],
48            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
49                view: target.depth_stencil_view(),
50                depth_ops: Some(wgpu::Operations {
51                    load: wgpu::LoadOp::Load,
52                    store: wgpu::StoreOp::Store,
53                }),
54                stencil_ops: None,
55            }),
56            timestamp_writes: None,
57            occlusion_query_set: None,
58            multiview_mask: None,
59        });
60    profiler.scope_pass("mesh::depth", &mut pass, |pass| {
61        pass.set_pipeline(&pipelines.get_or_init::<MeshItemDepthPipeline>(&ctx));
62        pass.set_bind_group(0, resolution.bind_group(), &[]);
63        pass.set_bind_group(1, viewport.bind_group(), &[]);
64        pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
65        pass.set_vertex_buffer(0, merged.vertices_buffer.buffer().slice(..));
66        pass.set_vertex_buffer(1, merged.mesh_ids_buffer.buffer().slice(..));
67        pass.set_vertex_buffer(2, merged.vertex_colors_buffer.buffer().slice(..));
68        pass.set_vertex_buffer(3, merged.vertex_normals_buffer.buffer().slice(..));
69        pass.set_index_buffer(
70            merged.indices_buffer.buffer().slice(..),
71            wgpu::IndexFormat::Uint32,
72        );
73        pass.draw_indexed(0..merged.total_indices(), 0, 0..1);
74    });
75}
76
77#[allow(clippy::too_many_arguments)]
78pub(crate) fn color(
79    mut render: RenderContext,
80    ctx: Res<WgpuContext>,
81    pipelines: Res<PipelinesPool>,
82    resolution: Res<ResolutionInfo>,
83    target: Res<FrameTarget>,
84    viewport: Res<ViewportGpuPacket>,
85    merged: Res<MeshItemsBuffer>,
86    profiler: Res<RenderProfiler>,
87) {
88    if merged.item_count() == 0 {
89        return;
90    }
91    let mut pass = render
92        .encoder()
93        .begin_render_pass(&wgpu::RenderPassDescriptor {
94            label: Some("Merged RenderMeshItem Color Render Pass"),
95            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
96                view: target.render_view(),
97                resolve_target: None,
98                depth_slice: None,
99                ops: wgpu::Operations {
100                    load: wgpu::LoadOp::Load,
101                    store: wgpu::StoreOp::Store,
102                },
103            })],
104            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
105                view: target.depth_stencil_view(),
106                depth_ops: Some(wgpu::Operations {
107                    load: wgpu::LoadOp::Load,
108                    store: wgpu::StoreOp::Store,
109                }),
110                stencil_ops: None,
111            }),
112            timestamp_writes: None,
113            occlusion_query_set: None,
114            multiview_mask: None,
115        });
116    profiler.scope_pass("mesh::color", &mut pass, |pass| {
117        pass.set_pipeline(&pipelines.get_or_init::<MeshItemColorPipeline>(&ctx));
118        pass.set_bind_group(0, resolution.bind_group(), &[]);
119        pass.set_bind_group(1, viewport.bind_group(), &[]);
120        pass.set_bind_group(2, merged.render_bind_group.as_ref().unwrap(), &[]);
121        pass.set_vertex_buffer(0, merged.vertices_buffer.buffer().slice(..));
122        pass.set_vertex_buffer(1, merged.mesh_ids_buffer.buffer().slice(..));
123        pass.set_vertex_buffer(2, merged.vertex_colors_buffer.buffer().slice(..));
124        pass.set_vertex_buffer(3, merged.vertex_normals_buffer.buffer().slice(..));
125        pass.set_index_buffer(
126            merged.indices_buffer.buffer().slice(..),
127            wgpu::IndexFormat::Uint32,
128        );
129        pass.draw_indexed(0..merged.total_indices(), 0, 0..1);
130    });
131}
132
133pub struct MeshItemColorPipeline {
134    pipeline: wgpu::RenderPipeline,
135}
136
137impl Deref for MeshItemColorPipeline {
138    type Target = wgpu::RenderPipeline;
139    fn deref(&self) -> &Self::Target {
140        &self.pipeline
141    }
142}
143
144impl GpuResource for MeshItemColorPipeline {
145    fn new(ctx: &WgpuContext) -> Self {
146        let module = &ctx
147            .device
148            .create_shader_module(wgpu::include_wgsl!("./shaders/mesh_item.wgsl"));
149        let layout = ctx
150            .device
151            .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
152                label: Some("RenderMeshItem Color Pipeline Layout"),
153                bind_group_layouts: &[
154                    Some(&ResolutionInfo::create_bind_group_layout(ctx)),
155                    Some(&ViewportBindGroup::bind_group_layout(ctx)),
156                    Some(&MeshItemsBuffer::render_bind_group_layout(ctx)),
157                ],
158                immediate_size: 0,
159            });
160        let vertex_buffer_layouts = MeshItemsBuffer::vertex_buffer_layouts().map(Some);
161        let pipeline = ctx
162            .device
163            .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
164                label: Some("RenderMeshItem Color Pipeline"),
165                layout: Some(&layout),
166                vertex: wgpu::VertexState {
167                    module,
168                    entry_point: Some("vs_main"),
169                    buffers: &vertex_buffer_layouts,
170                    compilation_options: wgpu::PipelineCompilationOptions::default(),
171                },
172                fragment: Some(wgpu::FragmentState {
173                    module,
174                    entry_point: Some("fs_color"),
175                    compilation_options: wgpu::PipelineCompilationOptions::default(),
176                    targets: &[Some(wgpu::ColorTargetState {
177                        format: OUTPUT_TEXTURE_FORMAT,
178                        blend: Some(wgpu::BlendState::ALPHA_BLENDING),
179                        write_mask: wgpu::ColorWrites::ALL,
180                    })],
181                }),
182                primitive: wgpu::PrimitiveState {
183                    topology: wgpu::PrimitiveTopology::TriangleList,
184                    ..Default::default()
185                },
186                depth_stencil: Some(wgpu::DepthStencilState {
187                    format: wgpu::TextureFormat::Depth32Float,
188                    depth_write_enabled: Some(false),
189                    depth_compare: Some(wgpu::CompareFunction::LessEqual),
190                    stencil: wgpu::StencilState::default(),
191                    bias: wgpu::DepthBiasState::default(),
192                }),
193                multisample: wgpu::MultisampleState {
194                    count: 1,
195                    mask: !0,
196                    alpha_to_coverage_enabled: false,
197                },
198                multiview_mask: None,
199                cache: None,
200            });
201        Self { pipeline }
202    }
203}
204
205pub struct MeshItemDepthPipeline {
206    pipeline: wgpu::RenderPipeline,
207}
208
209impl Deref for MeshItemDepthPipeline {
210    type Target = wgpu::RenderPipeline;
211    fn deref(&self) -> &Self::Target {
212        &self.pipeline
213    }
214}
215
216impl GpuResource for MeshItemDepthPipeline {
217    fn new(ctx: &WgpuContext) -> Self {
218        let module = &ctx
219            .device
220            .create_shader_module(wgpu::include_wgsl!("./shaders/mesh_item.wgsl"));
221        let layout = ctx
222            .device
223            .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
224                label: Some("RenderMeshItem Depth Pipeline Layout"),
225                bind_group_layouts: &[
226                    Some(&ResolutionInfo::create_bind_group_layout(ctx)),
227                    Some(&ViewportBindGroup::bind_group_layout(ctx)),
228                    Some(&MeshItemsBuffer::render_bind_group_layout(ctx)),
229                ],
230                immediate_size: 0,
231            });
232        let vertex_buffer_layouts = MeshItemsBuffer::vertex_buffer_layouts().map(Some);
233        let pipeline = ctx
234            .device
235            .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
236                label: Some("RenderMeshItem Depth Pipeline"),
237                layout: Some(&layout),
238                vertex: wgpu::VertexState {
239                    module,
240                    entry_point: Some("vs_main"),
241                    buffers: &vertex_buffer_layouts,
242                    compilation_options: wgpu::PipelineCompilationOptions::default(),
243                },
244                fragment: Some(wgpu::FragmentState {
245                    module,
246                    entry_point: Some("fs_depth"),
247                    compilation_options: wgpu::PipelineCompilationOptions::default(),
248                    targets: &[],
249                }),
250                primitive: wgpu::PrimitiveState {
251                    topology: wgpu::PrimitiveTopology::TriangleList,
252                    ..Default::default()
253                },
254                depth_stencil: Some(wgpu::DepthStencilState {
255                    format: wgpu::TextureFormat::Depth32Float,
256                    depth_write_enabled: Some(true),
257                    depth_compare: Some(wgpu::CompareFunction::Less),
258                    stencil: wgpu::StencilState::default(),
259                    bias: wgpu::DepthBiasState::default(),
260                }),
261                multisample: wgpu::MultisampleState {
262                    count: 1,
263                    mask: !0,
264                    alpha_to_coverage_enabled: false,
265                },
266                multiview_mask: None,
267                cache: None,
268            });
269        Self { pipeline }
270    }
271}