nvgx_wgpu/
renderer.rs

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}