Skip to main content

dioxus_native/
dioxus_renderer.rs

1use std::rc::Rc;
2use std::sync::Arc;
3use std::{any::Any, cell::RefCell};
4
5use anyrender::{CompositeAlphaMode, RenderContext, RendererConfig, WindowRenderer};
6use peniko::Color;
7
8// Renderer imports
9cfg_if::cfg_if! {
10    if #[cfg(feature = "vello")] {
11        pub use anyrender_vello::{
12            VelloRendererOptions as InnerRendererOptions, VelloWindowRenderer as InnerRenderer,
13            wgpu::{Features, Limits},
14        };
15    } else if #[cfg(feature = "vello-cpu-base")] {
16        use anyrender_vello_cpu::VelloCpuWindowRenderer as InnerRenderer;
17    } else if #[cfg(feature = "skia")] {
18        use anyrender_skia::SkiaWindowRenderer as InnerRenderer;
19    } else if #[cfg(feature = "skia-raster-base")] {
20        use anyrender_skia::raster::SkiaRasterWindowRenderer as InnerRenderer;
21    } else if #[cfg(feature = "vello-hybrid")] {
22        pub use anyrender_vello_hybrid::{
23            VelloHybridRendererOptions as InnerRendererOptions, VelloHybridWindowRenderer as InnerRenderer,
24            wgpu::{Features, Limits},
25        };
26    } else {
27        compile_error!("At least one renderer feature must be enabled");
28    }
29}
30
31/// Renderer configuration for [`DioxusNativeWindowRenderer`].
32///
33/// Fields that only apply to the GPU-backed `vello`/`vello-hybrid` renderers
34/// (`features`/`limits`) are only present when one of those features is enabled.
35#[derive(Default)]
36pub struct RendererOptions {
37    /// Base (background) color used to clear each frame.
38    pub base_color: Option<Color>,
39    /// Alpha mode used when compositing the window surface.
40    pub alpha_mode: Option<CompositeAlphaMode>,
41    /// wgpu features to request from the GPU adapter.
42    #[cfg(any(feature = "vello", feature = "vello-hybrid"))]
43    pub features: Option<Features>,
44    /// wgpu limits to request from the GPU adapter.
45    #[cfg(any(feature = "vello", feature = "vello-hybrid"))]
46    pub limits: Option<Limits>,
47}
48
49#[derive(Clone)]
50pub struct DioxusNativeWindowRenderer {
51    inner: Rc<RefCell<InnerRenderer>>,
52}
53
54impl Default for DioxusNativeWindowRenderer {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60impl DioxusNativeWindowRenderer {
61    pub fn new() -> Self {
62        Self::with_options(RendererOptions::default())
63    }
64
65    #[cfg(any(feature = "vello-hybrid", feature = "vello"))]
66    pub fn with_features_and_limits(features: Option<Features>, limits: Option<Limits>) -> Self {
67        Self::with_options(RendererOptions {
68            features,
69            limits,
70            ..Default::default()
71        })
72    }
73
74    /// Build a renderer from the given [`RendererOptions`].
75    ///
76    /// `base_color` and `alpha_mode` are forwarded to the active renderer via
77    /// [`anyrender::RendererConfig`]; renderers that don't support a particular
78    /// option simply ignore it. `features`/`limits` are only applied by the
79    /// GPU-backed `vello`/`vello-hybrid` renderers.
80    pub fn with_options(options: RendererOptions) -> Self {
81        let mut config = RendererConfig::default();
82        config.base_color = options.base_color;
83        config.composite_alpha_mode = options.alpha_mode;
84
85        cfg_if::cfg_if! {
86            if #[cfg(any(feature = "vello", feature = "vello-hybrid"))] {
87                let mut inner_options: InnerRendererOptions = config.into();
88                if let Some(features) = options.features {
89                    inner_options = inner_options.features(features);
90                }
91                if let Some(limits) = options.limits {
92                    inner_options = inner_options.limits(limits);
93                }
94                let inner_renderer = InnerRenderer::with_options(inner_options);
95            } else {
96                let inner_renderer = InnerRenderer::with_options(config);
97            }
98        }
99
100        Self::with_inner_renderer(inner_renderer)
101    }
102
103    fn with_inner_renderer(inner_renderer: InnerRenderer) -> Self {
104        Self {
105            inner: Rc::new(RefCell::new(inner_renderer)),
106        }
107    }
108}
109
110impl RenderContext for DioxusNativeWindowRenderer {
111    fn try_register_custom_resource(
112        &mut self,
113        resource: Box<dyn Any>,
114    ) -> Result<anyrender::ResourceId, anyrender::RegisterResourceError> {
115        self.inner
116            .borrow_mut()
117            .try_register_custom_resource(resource)
118    }
119
120    fn unregister_resource(&mut self, resource_id: anyrender::ResourceId) {
121        self.inner.borrow_mut().unregister_resource(resource_id)
122    }
123
124    fn renderer_specific_context(&self) -> Option<Box<dyn Any>> {
125        self.inner.borrow_mut().renderer_specific_context()
126    }
127}
128impl WindowRenderer for DioxusNativeWindowRenderer {
129    type ScenePainter<'a>
130        = <InnerRenderer as WindowRenderer>::ScenePainter<'a>
131    where
132        Self: 'a;
133
134    fn resume<F: FnOnce() + 'static>(
135        &mut self,
136        window: Arc<dyn anyrender::WindowHandle>,
137        width: u32,
138        height: u32,
139        on_ready: F,
140    ) {
141        self.inner
142            .borrow_mut()
143            .resume(window, width, height, on_ready)
144    }
145
146    fn complete_resume(&mut self) -> bool {
147        self.inner.borrow_mut().complete_resume()
148    }
149
150    fn suspend(&mut self) {
151        self.inner.borrow_mut().suspend()
152    }
153
154    fn is_active(&self) -> bool {
155        self.inner.borrow().is_active()
156    }
157
158    fn is_pending(&self) -> bool {
159        self.inner.borrow().is_pending()
160    }
161
162    fn set_size(&mut self, width: u32, height: u32) {
163        self.inner.borrow_mut().set_size(width, height)
164    }
165
166    fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F) {
167        self.inner.borrow_mut().render(draw_fn)
168    }
169}