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}