1use std::ops::Range;
2use std::sync::Arc;
3
4use nvgx::{BufferUsage, VertexSlice};
5use wgpu::{Extent3d, Origin2d};
6
7use crate::{
8 call::{Call, GpuPath},
9 unifroms::{RenderCommand, ShaderType},
10};
11
12use super::{call::CallType, mesh::Mesh, Renderer};
13
14impl nvgx::RendererDevice for Renderer {
15 type VertexBuffer = Arc<wgpu::Buffer>;
16
17 fn edge_antialias(&self) -> bool {
18 return self.resources.config.antialias;
19 }
20
21 fn create_vertex_buffer(
22 &mut self,
23 buffer_size: usize,
24 _usage: BufferUsage,
25 ) -> anyhow::Result<Self::VertexBuffer> {
26 return Ok(Arc::new(Mesh::create_buffer(&self.device, buffer_size)));
27 }
28
29 fn update_vertex_buffer(
30 &mut self,
31 buffer: Option<&Self::VertexBuffer>,
32 data: &[u8],
33 ) -> anyhow::Result<()> {
34 if let Some(buffer) = buffer {
35 self.resources
36 .mesh
37 .update_buffer(&self.queue, buffer.as_ref(), data)?;
38 } else {
39 self.resources
40 .mesh
41 .update_inner_buffer(&self.device, &self.queue, data);
42 };
43 Ok(())
44 }
45
46 fn resize(&mut self, _width: u32, _height: u32) -> anyhow::Result<()> {
47 self.surface_config.width = _width;
48 self.surface_config.height = _height;
49 self.surface.configure(&self.device, &self.surface_config);
50 self.resources
51 .texture_manager
52 .configure_stencil(&self.device, &self.surface_config);
53 Ok(())
54 }
55
56 fn create_texture(
57 &mut self,
58 texture_type: nvgx::TextureType,
59 width: u32,
60 height: u32,
61 flags: nvgx::ImageFlags,
62 data: Option<&[u8]>,
63 ) -> anyhow::Result<nvgx::ImageId> {
64 Ok(self.resources.texture_manager.create(
65 &self.device,
66 &self.queue,
67 wgpu::Extent3d {
68 width: width,
69 height: height,
70 depth_or_array_layers: 1,
71 },
72 flags,
73 texture_type,
74 data,
75 ) as nvgx::ImageId)
76 }
77
78 fn delete_texture(&mut self, img: nvgx::ImageId) -> anyhow::Result<()> {
79 self.resources.texture_manager.remove(img as usize);
80 Ok(())
81 }
82
83 fn update_texture(
84 &mut self,
85 img: nvgx::ImageId,
86 x: u32,
87 y: u32,
88 width: u32,
89 height: u32,
90 data: &[u8],
91 ) -> anyhow::Result<()> {
92 let texture = self
93 .resources
94 .texture_manager
95 .get_mut(img as usize)
96 .ok_or_else(|| anyhow::anyhow!("Texture not found"))?;
97 texture.update(
98 &self.queue,
99 data,
100 Origin2d { x, y },
101 Extent3d {
102 width: width,
103 height: height,
104 depth_or_array_layers: 1,
105 },
106 );
107 Ok(())
108 }
109
110 fn texture_size(&self, img: nvgx::ImageId) -> anyhow::Result<(u32, u32)> {
111 let texture = self
112 .resources
113 .texture_manager
114 .get(img as usize)
115 .ok_or_else(|| anyhow::anyhow!("Texture not found"))?;
116 let size = texture.size();
117 Ok((size.width, size.height))
118 }
119
120 fn viewport(&mut self, extent: nvgx::Extent, _device_pixel_ratio: f32) -> anyhow::Result<()> {
121 self.resources.viewsize_uniform.value = extent;
122 Ok(())
123 }
124
125 #[inline]
126 fn cancel(&mut self) -> anyhow::Result<()> {
127 self.resources.calls.clear();
128 self.resources.paths.clear();
129 self.resources.render_unifrom.value.clear();
130 Ok(())
131 }
132
133 fn flush(&mut self) -> anyhow::Result<()> {
134 self.resources
135 .viewsize_uniform
136 .update_buffer(&self.device, &self.queue);
137 self.resources
138 .render_unifrom
139 .update_buffer(&self.device, &self.queue);
140
141 if let Some((image, stencil_view)) = self.target_fb.as_ref() {
142 let texture = self.resources.texture_manager.get(*image).unwrap();
143 self.resources.render(
144 &self.device,
145 &self.queue,
146 &texture.view,
147 texture.texture_type,
148 &stencil_view,
149 &mut self.pipeline_manager,
150 self.clear_cmd.take(),
151 );
152 } else {
153 let output = self.surface.get_current_texture().unwrap();
154 let view = output
155 .texture
156 .create_view(&wgpu::TextureViewDescriptor::default());
157
158 self.resources.render(
159 &self.device,
160 &self.queue,
161 &view,
162 self.resources.config.format,
163 self.resources.texture_manager.stencil_view(),
164 &mut self.pipeline_manager,
165 self.clear_cmd.take(),
166 );
167 output.present();
168 };
169 return self.cancel();
170 }
171
172 fn fill(
173 &mut self,
174 vertex_buffer: Option<Self::VertexBuffer>,
175 instances: Option<(Self::VertexBuffer, Range<u32>)>,
176 paint: &nvgx::PaintPattern,
177 composite_operation: nvgx::CompositeOperationState,
178 fill_type: nvgx::PathFillType,
179 scissor: &nvgx::Scissor,
180 fringe: f32,
181 bounds_offset: Option<usize>,
182 paths: &[nvgx::PathSlice],
183 ) -> anyhow::Result<()> {
184 let path_offset = self.resources.paths.len();
185 let mut fill_vertex_count = 0;
186 self.resources.paths.extend(paths.iter().filter_map(|p| {
187 let fill = p.get_fill();
188 if fill.count < 3 {
189 None
190 } else {
191 fill_vertex_count += fill.count;
192 Some(GpuPath {
193 fill,
194 stroke: p.get_stroke(),
195 })
196 }
197 }));
198
199 self.resources
200 .mesh
201 .update_indices(&self.device, &self.queue, fill_vertex_count as u64);
202
203 let call = Call {
204 call_type: if bounds_offset.is_some() {
205 crate::call::CallType::Fill(fill_type)
206 } else {
207 crate::call::CallType::ConvexFill
208 },
209 image: paint.image,
210 path_range: path_offset..self.resources.paths.len(),
211 triangle: if let Some(offset) = bounds_offset {
212 VertexSlice { offset, count: 4 }
213 } else {
214 Default::default()
215 },
216 uniform_offset: self.resources.render_unifrom.offset(),
217 blend_func: composite_operation,
218 vertex_buffer,
219 instances,
220 };
221
222 if let CallType::Fill(_) = call.call_type {
223 self.resources.render_unifrom.value.push(RenderCommand {
224 stroke_thr: -1.0,
225 render_type: ShaderType::Simple as u32,
226 ..Default::default()
227 });
228 self.resources.render_unifrom.value.push(RenderCommand::new(
229 &self, paint, scissor, fringe, fringe, -1.0,
230 ));
231 } else {
232 self.resources.render_unifrom.value.push(RenderCommand::new(
233 &self, paint, scissor, fringe, fringe, -1.0,
234 ));
235 }
236 self.resources.calls.push(call);
237 Ok(())
238 }
239
240 fn stroke(
241 &mut self,
242 vertex_buffer: Option<Self::VertexBuffer>,
243 instances: Option<(Self::VertexBuffer, Range<u32>)>,
244 paint: &nvgx::PaintPattern,
245 composite_operation: nvgx::CompositeOperationState,
246 scissor: &nvgx::Scissor,
247 fringe: f32,
248 stroke_width: f32,
249 paths: &[nvgx::PathSlice],
250 ) -> anyhow::Result<()> {
251 let path_offset = self.resources.paths.len();
252
253 self.resources.paths.extend(paths.iter().filter_map(|p| {
254 let stroke = p.get_stroke();
255 Some(GpuPath {
256 stroke: stroke,
257 ..Default::default()
258 })
259 }));
260
261 let call = Call {
262 call_type: CallType::Stroke,
263 image: paint.image,
264 path_range: path_offset..self.resources.paths.len(),
265 uniform_offset: self.resources.render_unifrom.offset(),
266 blend_func: composite_operation,
267 vertex_buffer,
268 triangle: VertexSlice::default(),
269 instances,
270 };
271
272 self.resources.render_unifrom.value.push(RenderCommand::new(
273 &self,
274 paint,
275 scissor,
276 stroke_width,
277 fringe,
278 -1.0,
279 ));
280 self.resources.calls.push(call);
281 Ok(())
282 }
283
284 fn triangles(
285 &mut self,
286 vertex_buffer: Option<Self::VertexBuffer>,
287 instances: Option<(Self::VertexBuffer, Range<u32>)>,
288 paint: &nvgx::PaintPattern,
289 composite_operation: nvgx::CompositeOperationState,
290 scissor: &nvgx::Scissor,
291 slice: VertexSlice,
292 ) -> anyhow::Result<()> {
293 let call = Call {
294 call_type: CallType::Triangles,
295 image: paint.image,
296 triangle: slice,
297 path_range: 0..0,
298 uniform_offset: self.resources.render_unifrom.offset(),
299 blend_func: composite_operation,
300 vertex_buffer,
301 instances,
302 };
303
304 self.resources.calls.push(call);
305
306 self.resources.render_unifrom.value.push(
307 RenderCommand::new(&self, paint, scissor, 1.0, 1.0, -1.0).set_type(ShaderType::Image),
308 );
309 Ok(())
310 }
311
312 fn clear(&mut self, color: nvgx::Color) -> anyhow::Result<()> {
313 self.cancel()?;
314 self.clear_cmd = Some(wgpu::Color {
315 r: color.r as f64,
316 g: color.g as f64,
317 b: color.b as f64,
318 a: color.a as f64,
319 });
320 Ok(())
321 }
322
323 #[cfg(feature = "wirelines")]
324 fn wirelines(
325 &mut self,
326 vertex_buffer: Option<Self::VertexBuffer>,
327 instances: Option<(Self::VertexBuffer, Range<u32>)>,
328 paint: &nvgx::PaintPattern,
329 composite_operation: nvgx::CompositeOperationState,
330 scissor: &nvgx::Scissor,
331 paths: &[nvgx::PathSlice],
332 ) -> anyhow::Result<()> {
333 let path_offset = self.resources.paths.len();
334
335 self.resources.paths.extend(paths.iter().filter_map(|p| {
336 let stroke = p.get_stroke();
337 Some(GpuPath {
338 stroke: stroke,
339 ..Default::default()
340 })
341 }));
342
343 let call = Call {
344 call_type: CallType::Lines,
345 image: paint.image,
346 path_range: path_offset..self.resources.paths.len(),
347 uniform_offset: self.resources.render_unifrom.offset(),
348 blend_func: composite_operation,
349 vertex_buffer,
350 triangle: VertexSlice::default(),
351 instances,
352 };
353
354 self.resources.calls.push(call);
355
356 self.resources
357 .render_unifrom
358 .value
359 .push(RenderCommand::new(&self, paint, scissor, 1.0, 1.0, -1.0));
360 Ok(())
361 }
362}