1use image::imageops::crop_imm;
2use std::sync::Arc;
3use wgpu::{
4 Adapter, Buffer, BufferAddress, BufferDescriptor, BufferUsages, CommandBuffer,
5 CommandEncoderDescriptor, Device, DeviceDescriptor, Extent3d, ImageCopyBuffer,
6 ImageCopyTexture, ImageDataLayout, LoadOp, MapMode, Operations, Origin3d, PowerPreference,
7 Queue, RenderPassColorAttachment, RenderPassDescriptor, RequestAdapterOptions, StoreOp,
8 Surface, SurfaceConfiguration, Texture, TextureAspect, TextureDescriptor, TextureDimension,
9 TextureFormat, TextureFormatFeatureFlags, TextureUsages, TextureView, TextureViewDescriptor,
10};
11use winit::dpi::Size;
12use winit::event::WindowEvent;
13use winit::window::Window;
14
15use crate::error::AvengerWgpuError;
16use crate::marks::instanced_mark::InstancedMarkRenderer;
17use crate::marks::multi::MultiMarkRenderer;
18use crate::marks::symbol::SymbolShader;
19use crate::marks::text::TextAtlasBuilderTrait;
20use avenger::marks::arc::ArcMark;
21use avenger::marks::area::AreaMark;
22use avenger::marks::group::Clip;
23use avenger::marks::image::ImageMark;
24use avenger::marks::line::LineMark;
25use avenger::marks::path::PathMark;
26use avenger::marks::trail::TrailMark;
27use avenger::{
28 marks::group::SceneGroup, marks::mark::SceneMark, marks::rect::RectMark, marks::rule::RuleMark,
29 marks::symbol::SymbolMark, marks::text::TextMark, scene_graph::SceneGraph,
30};
31
32pub enum MarkRenderer {
33 Instanced(InstancedMarkRenderer),
34 Multi(Box<MultiMarkRenderer>),
35}
36
37#[derive(Debug, Copy, Clone)]
38pub struct CanvasDimensions {
39 pub size: [f32; 2],
40 pub scale: f32,
41}
42
43impl CanvasDimensions {
44 pub fn to_physical_width(&self) -> u32 {
45 (self.size[0] * self.scale) as u32
46 }
47
48 pub fn to_physical_height(&self) -> u32 {
49 (self.size[1] * self.scale) as u32
50 }
51
52 pub fn to_physical_size(&self) -> winit::dpi::PhysicalSize<u32> {
53 winit::dpi::PhysicalSize {
54 width: self.to_physical_width(),
55 height: self.to_physical_height(),
56 }
57 }
58}
59
60pub type TextBuildCtor = Arc<fn() -> Box<dyn TextAtlasBuilderTrait>>;
61
62#[derive(Default)]
63pub struct CanvasConfig {
64 pub text_builder_ctor: Option<TextBuildCtor>,
65}
66
67pub trait Canvas {
68 fn add_mark_renderer(&mut self, mark_renderer: MarkRenderer);
69 fn clear_mark_renderer(&mut self);
70 fn device(&self) -> &Device;
71 fn queue(&self) -> &Queue;
72 fn dimensions(&self) -> CanvasDimensions;
73
74 fn texture_format(&self) -> TextureFormat;
75
76 fn sample_count(&self) -> u32;
77
78 fn get_multi_renderer(&mut self) -> &mut MultiMarkRenderer;
79
80 fn add_arc_mark(
81 &mut self,
82 mark: &ArcMark,
83 origin: [f32; 2],
84 group_clip: &Clip,
85 ) -> Result<(), AvengerWgpuError> {
86 self.get_multi_renderer()
87 .add_arc_mark(mark, origin, group_clip)?;
88 Ok(())
89 }
90
91 fn add_path_mark(
92 &mut self,
93 mark: &PathMark,
94 origin: [f32; 2],
95 group_clip: &Clip,
96 ) -> Result<(), AvengerWgpuError> {
97 self.get_multi_renderer()
98 .add_path_mark(mark, origin, group_clip)?;
99 Ok(())
100 }
101
102 fn add_line_mark(
103 &mut self,
104 mark: &LineMark,
105 origin: [f32; 2],
106 group_clip: &Clip,
107 ) -> Result<(), AvengerWgpuError> {
108 self.get_multi_renderer()
109 .add_line_mark(mark, origin, group_clip)?;
110 Ok(())
111 }
112
113 fn add_trail_mark(
114 &mut self,
115 mark: &TrailMark,
116 origin: [f32; 2],
117 group_clip: &Clip,
118 ) -> Result<(), AvengerWgpuError> {
119 self.get_multi_renderer()
120 .add_trail_mark(mark, origin, group_clip)?;
121 Ok(())
122 }
123
124 fn add_area_mark(
125 &mut self,
126 mark: &AreaMark,
127 origin: [f32; 2],
128 group_clip: &Clip,
129 ) -> Result<(), AvengerWgpuError> {
130 self.get_multi_renderer()
131 .add_area_mark(mark, origin, group_clip)?;
132 Ok(())
133 }
134
135 fn add_symbol_mark(
136 &mut self,
137 mark: &SymbolMark,
138 origin: [f32; 2],
139 group_clip: &Clip,
140 ) -> Result<(), AvengerWgpuError> {
141 if mark.len >= 10000
142 && mark.gradients.is_empty()
143 && matches!(group_clip, Clip::None | Clip::Rect { .. })
144 {
145 self.add_mark_renderer(MarkRenderer::Instanced(InstancedMarkRenderer::new(
146 self.device(),
147 self.texture_format(),
148 self.sample_count(),
149 Box::new(SymbolShader::from_symbol_mark(
150 mark,
151 self.dimensions(),
152 origin,
153 )?),
154 group_clip.maybe_clip(mark.clip),
155 self.dimensions().scale,
156 )));
157 } else {
158 self.get_multi_renderer()
159 .add_symbol_mark(mark, origin, group_clip)?;
160 }
161
162 Ok(())
163 }
164
165 fn add_rect_mark(
166 &mut self,
167 mark: &RectMark,
168 origin: [f32; 2],
169 group_clip: &Clip,
170 ) -> Result<(), AvengerWgpuError> {
171 self.get_multi_renderer()
172 .add_rect_mark(mark, origin, group_clip)?;
173 Ok(())
174 }
175
176 fn add_rule_mark(
177 &mut self,
178 mark: &RuleMark,
179 origin: [f32; 2],
180 group_clip: &Clip,
181 ) -> Result<(), AvengerWgpuError> {
182 self.get_multi_renderer()
183 .add_rule_mark(mark, origin, group_clip)?;
184 Ok(())
185 }
186
187 fn add_text_mark(
188 &mut self,
189 mark: &TextMark,
190 origin: [f32; 2],
191 group_clip: &Clip,
192 ) -> Result<(), AvengerWgpuError> {
193 self.get_multi_renderer()
194 .add_text_mark(mark, origin, group_clip)?;
195 Ok(())
196 }
197
198 fn add_image_mark(
199 &mut self,
200 mark: &ImageMark,
201 origin: [f32; 2],
202 group_clip: &Clip,
203 ) -> Result<(), AvengerWgpuError> {
204 self.get_multi_renderer()
205 .add_image_mark(mark, origin, group_clip)?;
206 Ok(())
207 }
208
209 fn add_group_mark(
210 &mut self,
211 group: &SceneGroup,
212 parent_origin: [f32; 2],
213 parent_clip: &Clip,
214 ) -> Result<(), AvengerWgpuError> {
215 if let Some(rect) = group.make_path_mark() {
217 self.add_path_mark(&rect, parent_origin, &group.clip)?;
218 }
219
220 let zindex = group.marks.iter().map(|m| m.zindex()).collect::<Vec<_>>();
222 let mut indices: Vec<usize> = (0..zindex.len()).collect();
223 indices.sort_by_key(|i| zindex[*i].unwrap_or(0));
224
225 let origin = [
227 parent_origin[0] + group.origin[0],
228 parent_origin[1] + group.origin[1],
229 ];
230
231 let clip = if let Clip::None = group.clip {
233 parent_clip.clone()
235 } else {
236 group.clip.translate(origin[0], origin[1])
238 };
239
240 for mark_ind in indices {
241 let mark = &group.marks[mark_ind];
242 match mark {
243 SceneMark::Arc(mark) => {
244 self.add_arc_mark(mark, origin, &clip)?;
245 }
246 SceneMark::Symbol(mark) => {
247 self.add_symbol_mark(mark, origin, &clip)?;
248 }
249 SceneMark::Rect(mark) => {
250 self.add_rect_mark(mark, origin, &clip)?;
251 }
252 SceneMark::Rule(mark) => {
253 self.add_rule_mark(mark, origin, &clip)?;
254 }
255 SceneMark::Path(mark) => {
256 self.add_path_mark(mark, origin, &clip)?;
257 }
258 SceneMark::Line(mark) => {
259 self.add_line_mark(mark, origin, &clip)?;
260 }
261 SceneMark::Trail(mark) => {
262 self.add_trail_mark(mark, origin, &clip)?;
263 }
264 SceneMark::Area(mark) => {
265 self.add_area_mark(mark, origin, &clip)?;
266 }
267 SceneMark::Text(mark) => {
268 self.add_text_mark(mark, origin, &clip)?;
269 }
270 SceneMark::Image(mark) => {
271 self.add_image_mark(mark, origin, &clip)?;
272 }
273 SceneMark::Group(group) => {
274 self.add_group_mark(group, origin, &clip)?;
275 }
276 }
277 }
278 Ok(())
279 }
280
281 #[tracing::instrument(skip_all)]
282 fn set_scene(&mut self, scene_graph: &SceneGraph) -> Result<(), AvengerWgpuError> {
283 self.clear_mark_renderer();
285
286 let zindex = scene_graph
288 .groups
289 .iter()
290 .map(|g| g.zindex)
291 .collect::<Vec<_>>();
292 let mut indices: Vec<usize> = (0..zindex.len()).collect();
293 indices.sort_by_key(|i| zindex[*i].unwrap_or(0));
294
295 for group_ind in &indices {
296 let group = &scene_graph.groups[*group_ind];
297 self.add_group_mark(group, scene_graph.origin, &Clip::None)?;
298 }
299
300 Ok(())
301 }
302}
303
304pub(crate) fn make_background_command<C: Canvas>(
306 canvas: &C,
307 texture_view: &TextureView,
308 resolve_target: Option<&TextureView>,
309) -> CommandBuffer {
310 let mut background_encoder =
311 canvas
312 .device()
313 .create_command_encoder(&CommandEncoderDescriptor {
314 label: Some("Render Background Encoder"),
315 });
316
317 {
318 let _render_pass = background_encoder.begin_render_pass(&RenderPassDescriptor {
319 label: Some("Render Pass"),
320 color_attachments: &[Some(RenderPassColorAttachment {
321 view: texture_view,
322 resolve_target,
323 ops: Operations {
324 load: LoadOp::Clear(wgpu::Color {
325 r: 1.0,
326 g: 1.0,
327 b: 1.0,
328 a: 1.0,
329 }),
330 store: StoreOp::Store,
331 },
332 })],
333 depth_stencil_attachment: None,
334 occlusion_query_set: None,
335 timestamp_writes: None,
336 });
337 }
338 background_encoder.finish()
339}
340
341pub(crate) fn make_wgpu_instance() -> wgpu::Instance {
342 wgpu::Instance::new(wgpu::InstanceDescriptor {
343 backends: wgpu::Backends::all(),
344 ..Default::default()
345 })
346}
347
348pub(crate) async fn make_wgpu_adapter(
349 instance: &wgpu::Instance,
350 compatible_surface: Option<&Surface<'_>>,
351) -> Result<Adapter, AvengerWgpuError> {
352 instance
353 .request_adapter(&RequestAdapterOptions {
354 power_preference: PowerPreference::default(),
355 compatible_surface,
356 force_fallback_adapter: false,
357 })
358 .await
359 .ok_or(AvengerWgpuError::MakeWgpuAdapterError)
360}
361
362pub(crate) async fn request_wgpu_device(
363 adapter: &Adapter,
364) -> Result<(Device, Queue), AvengerWgpuError> {
365 Ok(adapter
366 .request_device(
367 &DeviceDescriptor {
368 label: None,
369 required_features: wgpu::Features::empty(),
370 required_limits: if cfg!(target_arch = "wasm32") {
373 wgpu::Limits::downlevel_webgl2_defaults()
374 } else {
375 wgpu::Limits::default()
376 },
377 },
378 None,
379 )
380 .await?)
381}
382
383pub(crate) fn create_multisampled_framebuffer(
384 device: &Device,
385 width: u32,
386 height: u32,
387 format: TextureFormat,
388 sample_count: u32,
389) -> TextureView {
390 let multisampled_texture_extent = wgpu::Extent3d {
391 width,
392 height,
393 depth_or_array_layers: 1,
394 };
395 let multisampled_frame_descriptor = &TextureDescriptor {
396 size: multisampled_texture_extent,
397 mip_level_count: 1,
398 sample_count,
399 dimension: TextureDimension::D2,
400 format,
401 usage: TextureUsages::RENDER_ATTACHMENT,
402 label: None,
403 view_formats: &[],
404 };
405
406 device
407 .create_texture(multisampled_frame_descriptor)
408 .create_view(&TextureViewDescriptor::default())
409}
410
411pub(crate) fn get_supported_sample_count(sample_flags: TextureFormatFeatureFlags) -> u32 {
412 if sample_flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X4) {
414 4
415 } else if sample_flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X2) {
416 2
417 } else {
418 1
419 }
420}
421
422pub struct WindowCanvas<'window> {
423 sample_count: u32,
424 surface_config: SurfaceConfiguration,
425 dimensions: CanvasDimensions,
426 marks: Vec<MarkRenderer>,
427 multi_renderer: Option<MultiMarkRenderer>,
428 config: CanvasConfig,
429
430 multisampled_framebuffer: TextureView,
433 queue: Queue,
434 device: Device,
435 surface: Surface<'window>,
436 window: Arc<Window>,
437}
438
439impl<'window> WindowCanvas<'window> {
440 pub async fn new(
441 window: Window,
442 dimensions: CanvasDimensions,
443 config: CanvasConfig,
444 ) -> Result<Self, AvengerWgpuError> {
445 let _ = window.request_inner_size(Size::Physical(dimensions.to_physical_size()));
446 let instance = make_wgpu_instance();
447 let window = Arc::new(window);
448 let surface = instance.create_surface(window.clone())?;
449 let adapter = make_wgpu_adapter(&instance, Some(&surface)).await?;
450 let (device, queue) = request_wgpu_device(&adapter).await?;
451
452 let surface_caps = surface.get_capabilities(&adapter);
453
454 let surface_format = surface_caps
456 .formats
457 .iter()
458 .copied()
459 .find(|f| !f.is_srgb())
460 .unwrap_or(surface_caps.formats[0]);
461
462 let surface_config = SurfaceConfiguration {
463 usage: TextureUsages::RENDER_ATTACHMENT,
464 format: surface_format,
465 width: dimensions.to_physical_width(),
466 height: dimensions.to_physical_height(),
467 present_mode: surface_caps.present_modes[0],
468 alpha_mode: surface_caps.alpha_modes[0],
469 view_formats: vec![],
470 desired_maximum_frame_latency: 2,
471 };
472 surface.configure(&device, &surface_config);
473
474 let format_flags = adapter.get_texture_format_features(surface_format).flags;
475 let sample_count = get_supported_sample_count(format_flags);
476 let multisampled_framebuffer = create_multisampled_framebuffer(
477 &device,
478 surface_config.width,
479 surface_config.height,
480 surface_format,
481 sample_count,
482 );
483
484 Ok(Self {
485 surface,
486 device,
487 queue,
488 multisampled_framebuffer,
489 sample_count,
490 surface_config,
491 dimensions,
492 window,
493 marks: Vec::new(),
494 multi_renderer: None,
495 config,
496 })
497 }
498
499 pub fn get_size(&self) -> winit::dpi::PhysicalSize<u32> {
500 self.dimensions.to_physical_size()
501 }
502
503 pub fn window(&self) -> &Window {
504 &self.window
505 }
506
507 pub fn resize(&mut self, _new_size: winit::dpi::PhysicalSize<u32>) {
508 }
515
516 #[allow(unused_variables)]
517 pub fn input(&mut self, event: &WindowEvent) -> bool {
518 false
519 }
520
521 pub fn update(&mut self) {}
522
523 pub fn render(&mut self) -> Result<(), AvengerWgpuError> {
524 let output = self.surface.get_current_texture()?;
525 let view = output
526 .texture
527 .create_view(&TextureViewDescriptor::default());
528
529 if let Some(multi_renderer) = self.multi_renderer.take() {
531 self.marks
532 .push(MarkRenderer::Multi(Box::new(multi_renderer)));
533 }
534
535 let background_command = if self.sample_count > 1 {
536 make_background_command(self, &self.multisampled_framebuffer, Some(&view))
537 } else {
538 make_background_command(self, &view, None)
539 };
540 let mut commands = vec![background_command];
541 let texture_format = self.texture_format();
542 for mark in &mut self.marks {
543 let command = match mark {
544 MarkRenderer::Instanced(renderer) => {
545 if self.sample_count > 1 {
546 renderer.render(&self.device, &self.multisampled_framebuffer, Some(&view))
547 } else {
548 renderer.render(&self.device, &view, None)
549 }
550 }
551 MarkRenderer::Multi(renderer) => {
552 if self.sample_count > 1 {
553 renderer.render(
554 &self.device,
555 &self.queue,
556 texture_format,
557 self.sample_count,
558 &self.multisampled_framebuffer,
559 Some(&view),
560 )
561 } else {
562 renderer.render(
563 &self.device,
564 &self.queue,
565 texture_format,
566 self.sample_count,
567 &view,
568 None,
569 )
570 }
571 }
572 };
573
574 commands.push(command);
575 }
576
577 self.queue.submit(commands);
578 output.present();
579
580 Ok(())
581 }
582}
583
584impl<'window> Canvas for WindowCanvas<'window> {
585 fn get_multi_renderer(&mut self) -> &mut MultiMarkRenderer {
586 if self.multi_renderer.is_none() {
587 self.multi_renderer = Some(MultiMarkRenderer::new(
588 self.dimensions,
589 self.config.text_builder_ctor.clone(),
590 ));
591 }
592 self.multi_renderer.as_mut().unwrap()
593 }
594
595 fn add_mark_renderer(&mut self, mark_renderer: MarkRenderer) {
596 if let Some(multi_renderer) = self.multi_renderer.take() {
597 self.marks
598 .push(MarkRenderer::Multi(Box::new(multi_renderer)));
599 }
600 self.marks.push(mark_renderer);
601 }
602
603 fn clear_mark_renderer(&mut self) {
604 self.marks.clear();
605 }
606
607 fn device(&self) -> &Device {
608 &self.device
609 }
610
611 fn queue(&self) -> &Queue {
612 &self.queue
613 }
614
615 fn dimensions(&self) -> CanvasDimensions {
616 self.dimensions
617 }
618
619 fn texture_format(&self) -> TextureFormat {
620 self.surface_config.format
621 }
622
623 fn sample_count(&self) -> u32 {
624 self.sample_count
625 }
626}
627
628pub struct PngCanvas {
629 sample_count: u32,
630 marks: Vec<MarkRenderer>,
631 dimensions: CanvasDimensions,
632 texture_view: TextureView,
633 output_buffer: Buffer,
634 texture: Texture,
635 texture_size: Extent3d,
636 padded_width: u32,
637 padded_height: u32,
638 multi_renderer: Option<MultiMarkRenderer>,
639 config: CanvasConfig,
640
641 multisampled_framebuffer: TextureView,
645 queue: Queue,
646 device: Device,
647}
648
649impl PngCanvas {
650 #[tracing::instrument(skip_all)]
651 pub async fn new(
652 dimensions: CanvasDimensions,
653 config: CanvasConfig,
654 ) -> Result<Self, AvengerWgpuError> {
655 let instance = make_wgpu_instance();
656 let adapter = make_wgpu_adapter(&instance, None).await?;
657 let (device, queue) = request_wgpu_device(&adapter).await?;
658 let texture_format = TextureFormat::Rgba8Unorm;
659 let format_flags = adapter.get_texture_format_features(texture_format).flags;
660 let sample_count = get_supported_sample_count(format_flags);
661 let texture_desc = TextureDescriptor {
662 size: Extent3d {
663 width: dimensions.to_physical_width(),
664 height: dimensions.to_physical_height(),
665 depth_or_array_layers: 1,
666 },
667 mip_level_count: 1,
668 sample_count: 1, dimension: TextureDimension::D2,
670 format: texture_format,
671 usage: TextureUsages::COPY_SRC | TextureUsages::RENDER_ATTACHMENT,
672 label: None,
673 view_formats: &[texture_format],
674 };
675 let texture_size = texture_desc.size;
676 let texture = device.create_texture(&texture_desc);
677 let texture_view = texture.create_view(&Default::default());
678
679 let u32_size = std::mem::size_of::<u32>() as u32;
681
682 let padded_width = (256.0 * (dimensions.to_physical_width() as f32 / 256.0).ceil()) as u32;
685 let padded_height =
686 (256.0 * (dimensions.to_physical_height() as f32 / 256.0).ceil()) as u32;
687
688 let output_buffer_size = (u32_size * padded_width * padded_height) as BufferAddress;
689 let output_buffer_desc = BufferDescriptor {
690 size: output_buffer_size,
691 usage: BufferUsages::COPY_DST
692 | BufferUsages::MAP_READ,
694 label: None,
695 mapped_at_creation: false,
696 };
697 let output_buffer = device.create_buffer(&output_buffer_desc);
698
699 let multisampled_framebuffer = create_multisampled_framebuffer(
700 &device,
701 dimensions.to_physical_width(),
702 dimensions.to_physical_height(),
703 texture_format,
704 sample_count,
705 );
706
707 Ok(Self {
708 device,
709 queue,
710 multisampled_framebuffer,
711 sample_count,
712 dimensions,
713 texture,
714 texture_view,
715 output_buffer,
716 texture_size,
717 padded_width,
718 padded_height,
719 marks: Vec::new(),
720 multi_renderer: None,
721 config,
722 })
723 }
724
725 #[tracing::instrument(skip_all)]
726 pub async fn render(&mut self) -> Result<image::RgbaImage, AvengerWgpuError> {
727 if let Some(multi_renderer) = self.multi_renderer.take() {
729 self.marks
730 .push(MarkRenderer::Multi(Box::new(multi_renderer)));
731 }
732
733 let background_command = if self.sample_count > 1 {
735 make_background_command(
736 self,
737 &self.multisampled_framebuffer,
738 Some(&self.texture_view),
739 )
740 } else {
741 make_background_command(self, &self.texture_view, None)
742 };
743
744 let mut commands = vec![background_command];
745 let texture_format = self.texture_format();
746 for mark in &mut self.marks {
747 let command = match mark {
748 MarkRenderer::Instanced(renderer) => {
749 if self.sample_count > 1 {
750 renderer.render(
751 &self.device,
752 &self.multisampled_framebuffer,
753 Some(&self.texture_view),
754 )
755 } else {
756 renderer.render(&self.device, &self.texture_view, None)
757 }
758 }
759 MarkRenderer::Multi(renderer) => {
760 if self.sample_count > 1 {
761 renderer.render(
762 &self.device,
763 &self.queue,
764 texture_format,
765 self.sample_count,
766 &self.multisampled_framebuffer,
767 Some(&self.texture_view),
768 )
769 } else {
770 renderer.render(
771 &self.device,
772 &self.queue,
773 texture_format,
774 self.sample_count,
775 &self.texture_view,
776 None,
777 )
778 }
779 }
780 };
781
782 commands.push(command);
783 }
784
785 self.queue.submit(commands);
786
787 let mut extract_encoder = self
789 .device
790 .create_command_encoder(&CommandEncoderDescriptor {
791 label: Some("Extract Texture Encoder"),
792 });
793
794 let u32_size = std::mem::size_of::<u32>() as u32;
795
796 extract_encoder.copy_texture_to_buffer(
797 ImageCopyTexture {
798 aspect: TextureAspect::All,
799 texture: &self.texture,
800 mip_level: 0,
801 origin: Origin3d::ZERO,
802 },
803 ImageCopyBuffer {
804 buffer: &self.output_buffer,
805 layout: ImageDataLayout {
806 offset: 0,
807 bytes_per_row: Some(u32_size * self.padded_width),
809 rows_per_image: Some(self.padded_height),
810 },
811 },
812 self.texture_size,
813 );
814 self.queue.submit(Some(extract_encoder.finish()));
815
816 let img = {
818 let buffer_slice = self.output_buffer.slice(..);
819
820 let (tx, rx) = futures_intrusive::channel::shared::oneshot_channel();
823 buffer_slice.map_async(MapMode::Read, move |result| {
824 tx.send(result).unwrap();
825 });
826 self.device.poll(wgpu::Maintain::Wait);
827
828 rx.receive().await.unwrap().unwrap();
830
831 let data = buffer_slice.get_mapped_range();
832 let img_buf =
833 image::RgbaImage::from_vec(self.padded_width, self.padded_height, data.to_vec())
834 .unwrap();
835
836 let cropped_img = crop_imm(
837 &img_buf,
838 0,
839 0,
840 self.dimensions.to_physical_width(),
841 self.dimensions.to_physical_height(),
842 );
843 cropped_img.to_image()
844 };
845
846 self.output_buffer.unmap();
847 Ok(img)
848 }
849}
850
851impl Canvas for PngCanvas {
852 fn get_multi_renderer(&mut self) -> &mut MultiMarkRenderer {
853 if self.multi_renderer.is_none() {
854 self.multi_renderer = Some(MultiMarkRenderer::new(
855 self.dimensions,
856 self.config.text_builder_ctor.clone(),
857 ));
858 }
859 self.multi_renderer.as_mut().unwrap()
860 }
861
862 fn add_mark_renderer(&mut self, mark_renderer: MarkRenderer) {
863 if let Some(multi_renderer) = self.multi_renderer.take() {
864 self.marks
865 .push(MarkRenderer::Multi(Box::new(multi_renderer)));
866 }
867 self.marks.push(mark_renderer);
868 }
869
870 fn clear_mark_renderer(&mut self) {
871 self.marks.clear();
872 }
873
874 fn device(&self) -> &Device {
875 &self.device
876 }
877
878 fn queue(&self) -> &Queue {
879 &self.queue
880 }
881
882 fn dimensions(&self) -> CanvasDimensions {
883 self.dimensions
884 }
885
886 fn texture_format(&self) -> TextureFormat {
887 self.texture.format()
888 }
889
890 fn sample_count(&self) -> u32 {
891 self.sample_count
892 }
893}