1use crate::{
2 RenderTextures,
3 pipelines::{
4 Map3dTo2dPipeline, VItemPipeline, map_3d_to_2d::ComputeBindGroup, vitem::RenderBindGroup,
5 },
6 utils::{PipelinesStorage, WgpuBuffer, WgpuContext, WgpuVecBuffer},
7};
8use glam::Vec4;
9use ranim_core::{
10 components::{rgba::Rgba, width::Width},
11 primitives::vitem::VItemPrimitive,
12};
13
14use super::{Primitive, RenderCommand, RenderResource};
15
16impl Primitive for VItemPrimitive {
17 type RenderInstance = VItemRenderInstance;
18}
19
20pub struct VItemRenderInstance {
22 pub(crate) points3d_buffer: WgpuVecBuffer<Vec4>,
24 pub(crate) points2d_buffer: WgpuVecBuffer<Vec4>, pub(crate) clip_info_buffer: WgpuVecBuffer<i32>,
28 pub(crate) point_cnt_buffer: Option<WgpuBuffer<u32>>,
30
31 pub(crate) fill_rgbas: WgpuVecBuffer<Rgba>,
33 pub(crate) stroke_rgbas: WgpuVecBuffer<Rgba>,
35 pub(crate) stroke_widths: WgpuVecBuffer<Width>,
37
38 pub(crate) compute_bind_group: Option<ComputeBindGroup>,
40
41 pub(crate) render_bind_group: Option<RenderBindGroup>,
43}
44
45impl RenderResource for VItemRenderInstance {
46 type Data = VItemPrimitive;
47
48 fn init(ctx: &WgpuContext, data: &Self::Data) -> Self {
49 let points3d_buffer = WgpuVecBuffer::new_init(
52 ctx,
53 Some("Points 3d Buffer"),
54 wgpu::BufferUsages::STORAGE
55 | wgpu::BufferUsages::COPY_DST
56 | wgpu::BufferUsages::COPY_SRC,
57 &data.points2d,
58 );
59 let points2d_buffer = WgpuVecBuffer::new_init(
61 ctx,
62 Some("Points 2d Buffer"),
63 wgpu::BufferUsages::STORAGE
64 | wgpu::BufferUsages::COPY_DST
65 | wgpu::BufferUsages::COPY_SRC,
66 &data.points2d,
67 );
68 let clip_info_buffer = WgpuVecBuffer::new_init(
70 ctx,
71 Some("Clip Info Buffer"),
72 wgpu::BufferUsages::STORAGE
73 | wgpu::BufferUsages::COPY_DST
74 | wgpu::BufferUsages::COPY_SRC,
75 &[i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0],
76 );
77 let point_cnt_buffer = WgpuBuffer::new_init(
79 ctx,
80 Some("Point Cnt Buffer"),
81 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
82 data.points2d.len() as u32,
83 );
84 let fill_rgbas = WgpuVecBuffer::new_init(
86 ctx,
87 Some("Fill Rgbas Buffer"),
88 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
89 &data.fill_rgbas,
90 );
91 let stroke_rgbas = WgpuVecBuffer::new_init(
93 ctx,
94 Some("Stroke Rgbas Buffer"),
95 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
96 &data.stroke_rgbas,
97 );
98 let stroke_widths = WgpuVecBuffer::new_init(
100 ctx,
101 Some("Stroke Widths Buffer"),
102 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
103 &data.stroke_widths,
104 );
105
106 let compute_bind_group = ComputeBindGroup::new(
108 ctx,
109 points3d_buffer.buffer.as_ref().unwrap(),
110 stroke_widths.buffer.as_ref().unwrap(),
111 points2d_buffer.buffer.as_ref().unwrap(),
112 clip_info_buffer.buffer.as_ref().unwrap(),
113 point_cnt_buffer.as_ref(),
114 );
115
116 let render_bind_group = RenderBindGroup::new(
118 ctx,
119 points2d_buffer.buffer.as_ref().unwrap(),
120 fill_rgbas.buffer.as_ref().unwrap(),
121 stroke_rgbas.buffer.as_ref().unwrap(),
122 stroke_widths.buffer.as_ref().unwrap(),
123 clip_info_buffer.buffer.as_ref().unwrap(),
124 );
125 Self {
128 points3d_buffer,
129 points2d_buffer,
130 clip_info_buffer,
131 point_cnt_buffer: Some(point_cnt_buffer),
132 fill_rgbas,
133 stroke_rgbas,
134 stroke_widths,
135 compute_bind_group: Some(compute_bind_group),
136 render_bind_group: Some(render_bind_group),
137 }
138 }
139 fn update(&mut self, ctx: &WgpuContext, data: &Self::Data) {
140 if self.point_cnt_buffer.is_none() {
141 self.point_cnt_buffer = Some(WgpuBuffer::new_init(
142 ctx,
143 Some("Point Cnt Buffer"),
144 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
145 data.points2d.len() as u32,
146 ));
147 } else {
148 self.point_cnt_buffer
149 .as_mut()
150 .unwrap()
151 .set(ctx, data.points2d.len() as u32);
152 }
153 if [
155 self.points3d_buffer.set(ctx, &data.points2d),
156 self.fill_rgbas.set(ctx, &data.fill_rgbas),
157 self.stroke_rgbas.set(ctx, &data.stroke_rgbas),
158 self.stroke_widths.set(ctx, &data.stroke_widths),
159 self.points2d_buffer.resize(ctx, data.points2d.len()),
160 self.clip_info_buffer
161 .set(ctx, &[i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0]),
162 self.compute_bind_group.is_none(),
164 ]
166 .iter()
167 .any(|x| *x)
168 {
169 self.compute_bind_group = Some(ComputeBindGroup::new(
170 ctx,
171 self.points3d_buffer.buffer.as_ref().unwrap(),
172 self.stroke_widths.buffer.as_ref().unwrap(),
173 self.points2d_buffer.buffer.as_ref().unwrap(),
174 self.clip_info_buffer.buffer.as_ref().unwrap(),
175 self.point_cnt_buffer.as_ref().unwrap().as_ref(),
176 ));
177 self.render_bind_group = Some(RenderBindGroup::new(
178 ctx,
179 self.points2d_buffer.buffer.as_ref().unwrap(),
180 self.fill_rgbas.buffer.as_ref().unwrap(),
181 self.stroke_rgbas.buffer.as_ref().unwrap(),
182 self.stroke_widths.buffer.as_ref().unwrap(),
183 self.clip_info_buffer.buffer.as_ref().unwrap(),
184 ));
185 }
186 }
187}
188
189impl RenderCommand for VItemRenderInstance {
190 fn encode_compute_pass_command(&self, cpass: &mut wgpu::ComputePass) {
191 cpass.set_bind_group(1, self.compute_bind_group.as_ref().unwrap().as_ref(), &[]);
192 cpass.dispatch_workgroups(self.points3d_buffer.len().div_ceil(256) as u32, 1, 1);
193 }
194 fn encode_render_pass_command(&self, rpass: &mut wgpu::RenderPass) {
195 rpass.set_bind_group(1, self.render_bind_group.as_ref().unwrap().as_ref(), &[]);
196 rpass.draw(0..4, 0..1);
197 }
198 fn encode_render_command(
199 &self,
200 ctx: &WgpuContext,
201 pipelines: &mut PipelinesStorage,
202 encoder: &mut wgpu::CommandEncoder,
203 uniforms_bind_group: &wgpu::BindGroup,
204 render_textures: &RenderTextures,
205 #[cfg(feature = "profiling")] profiler: &mut wgpu_profiler::GpuProfiler,
206 ) {
207 #[cfg(feature = "profiling")]
208 let mut scope = profiler.scope("vitem rendering", encoder);
209 {
210 #[cfg(feature = "profiling")]
211 let mut cpass = scope.scoped_compute_pass("VItem Map Points Compute Pass");
212 #[cfg(not(feature = "profiling"))]
213 let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
214 label: Some("VItem Map Points Compute Pass"),
215 timestamp_writes: None,
216 });
217 cpass.set_pipeline(pipelines.get_or_init::<Map3dTo2dPipeline>(ctx));
218 cpass.set_bind_group(0, uniforms_bind_group, &[]);
219
220 cpass.set_bind_group(1, self.compute_bind_group.as_ref().unwrap().as_ref(), &[]);
221 cpass.dispatch_workgroups(self.points3d_buffer.len().div_ceil(256) as u32, 1, 1);
222 }
223 {
224 let RenderTextures {
225 render_view,
227 ..
228 } = render_textures;
229 let rpass_desc = wgpu::RenderPassDescriptor {
230 label: Some("VItem Render Pass"),
231 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
232 depth_slice: None,
235 view: render_view,
236 resolve_target: None,
237 ops: wgpu::Operations {
238 load: wgpu::LoadOp::Load,
239 store: wgpu::StoreOp::Store,
240 },
241 })],
242 depth_stencil_attachment: None,
243 timestamp_writes: None,
244 occlusion_query_set: None,
245 };
246 #[cfg(feature = "profiling")]
247 let mut rpass = scope.scoped_render_pass("VItem Render Pass", rpass_desc);
248 #[cfg(not(feature = "profiling"))]
249 let mut rpass = encoder.begin_render_pass(&rpass_desc);
250 rpass.set_pipeline(pipelines.get_or_init::<VItemPipeline>(ctx));
251 rpass.set_bind_group(0, uniforms_bind_group, &[]);
252
253 rpass.set_bind_group(1, self.render_bind_group.as_ref().unwrap().as_ref(), &[]);
254 rpass.draw(0..4, 0..1);
255 }
256 }
257 fn debug(&self, _ctx: &WgpuContext) {
258 }
262}