oxiui_render_soft/
backend_switch.rs1use oxiui_core::{
28 geometry::Size,
29 paint::{DrawList, RenderBackend},
30 UiError,
31};
32
33use crate::SoftBackend;
34
35#[cfg(feature = "wgpu-compat")]
36use oxiui_render_wgpu::WgpuBackend;
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum BackendKind {
45 Soft,
47 #[cfg(feature = "wgpu-compat")]
49 Wgpu,
50}
51
52pub enum DynBackend {
67 Soft(Box<SoftBackend>),
69 #[cfg(feature = "wgpu-compat")]
71 Wgpu(Box<WgpuBackend>),
72}
73
74impl DynBackend {
75 pub fn soft(width: u32, height: u32) -> Self {
77 DynBackend::Soft(Box::new(SoftBackend::new(width, height)))
78 }
79
80 #[cfg(feature = "wgpu-compat")]
84 pub fn wgpu(backend: WgpuBackend) -> Self {
85 DynBackend::Wgpu(Box::new(backend))
86 }
87
88 pub fn kind(&self) -> BackendKind {
90 match self {
91 DynBackend::Soft(_) => BackendKind::Soft,
92 #[cfg(feature = "wgpu-compat")]
93 DynBackend::Wgpu(_) => BackendKind::Wgpu,
94 }
95 }
96
97 pub fn is_soft(&self) -> bool {
99 matches!(self, DynBackend::Soft(_))
100 }
101
102 #[cfg(feature = "wgpu-compat")]
104 pub fn is_wgpu(&self) -> bool {
105 matches!(self, DynBackend::Wgpu(_))
106 }
107
108 pub fn as_soft(&self) -> Option<&SoftBackend> {
110 match self {
111 DynBackend::Soft(b) => Some(b.as_ref()),
112 #[cfg(feature = "wgpu-compat")]
113 _ => None,
114 }
115 }
116
117 pub fn as_soft_mut(&mut self) -> Option<&mut SoftBackend> {
119 match self {
120 DynBackend::Soft(b) => Some(b.as_mut()),
121 #[cfg(feature = "wgpu-compat")]
122 _ => None,
123 }
124 }
125}
126
127impl RenderBackend for DynBackend {
128 fn execute(&mut self, list: &DrawList) -> Result<(), UiError> {
129 match self {
130 DynBackend::Soft(b) => b.execute(list),
131 #[cfg(feature = "wgpu-compat")]
132 DynBackend::Wgpu(b) => b.execute(list),
133 }
134 }
135
136 fn surface_size(&self) -> Size {
137 match self {
138 DynBackend::Soft(b) => b.surface_size(),
139 #[cfg(feature = "wgpu-compat")]
140 DynBackend::Wgpu(b) => b.surface_size(),
141 }
142 }
143
144 fn supports_blur(&self) -> bool {
145 match self {
146 DynBackend::Soft(b) => b.supports_blur(),
147 #[cfg(feature = "wgpu-compat")]
148 DynBackend::Wgpu(b) => b.supports_blur(),
149 }
150 }
151
152 fn supports_gradients(&self) -> bool {
153 match self {
154 DynBackend::Soft(b) => b.supports_gradients(),
155 #[cfg(feature = "wgpu-compat")]
156 DynBackend::Wgpu(b) => b.supports_gradients(),
157 }
158 }
159
160 fn supports_paths(&self) -> bool {
161 match self {
162 DynBackend::Soft(b) => b.supports_paths(),
163 #[cfg(feature = "wgpu-compat")]
164 DynBackend::Wgpu(b) => b.supports_paths(),
165 }
166 }
167
168 fn supports_images(&self) -> bool {
169 match self {
170 DynBackend::Soft(b) => b.supports_images(),
171 #[cfg(feature = "wgpu-compat")]
172 DynBackend::Wgpu(b) => b.supports_images(),
173 }
174 }
175
176 fn supports_text(&self) -> bool {
177 match self {
178 DynBackend::Soft(b) => b.supports_text(),
179 #[cfg(feature = "wgpu-compat")]
180 DynBackend::Wgpu(b) => b.supports_text(),
181 }
182 }
183
184 fn supports_blend_modes(&self) -> bool {
185 match self {
186 DynBackend::Soft(b) => b.supports_blend_modes(),
187 #[cfg(feature = "wgpu-compat")]
188 DynBackend::Wgpu(b) => b.supports_blend_modes(),
189 }
190 }
191
192 fn supports_backdrop_blur(&self) -> bool {
193 match self {
194 DynBackend::Soft(b) => b.supports_backdrop_blur(),
195 #[cfg(feature = "wgpu-compat")]
196 DynBackend::Wgpu(b) => b.supports_backdrop_blur(),
197 }
198 }
199}
200
201#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn dyn_backend_soft_kind() {
211 let b = DynBackend::soft(64, 64);
212 assert_eq!(b.kind(), BackendKind::Soft);
213 assert!(b.is_soft());
214 assert_eq!(b.surface_size(), Size::new(64.0, 64.0));
215 }
216
217 #[test]
218 fn dyn_backend_soft_supports_capabilities() {
219 let b = DynBackend::soft(32, 32);
220 assert!(b.supports_blur());
222 assert!(b.supports_gradients());
223 assert!(b.supports_paths());
224 assert!(b.supports_images());
225 }
226
227 #[test]
228 fn dyn_backend_soft_execute_fill_rect() {
229 use oxiui_core::geometry::{Rect, Size};
230 use oxiui_core::paint::DrawList;
231 use oxiui_core::Color;
232
233 let mut b = DynBackend::soft(100, 100);
234 let mut list = DrawList::new();
235 list.push_rect(Rect::new(10.0, 10.0, 20.0, 20.0), Color(255, 0, 0, 255));
236 let result = b.execute(&list);
237 assert!(result.is_ok(), "execute must not fail: {result:?}");
238 let fb_pixel = b.as_soft().and_then(|s| s.frame().get_rgba(20, 20));
240 if let Some((r, _, _, _)) = fb_pixel {
241 assert!(r > 200, "center pixel should be red: r={r}");
242 }
243 let _ = Size::new(0.0, 0.0);
245 }
246
247 #[test]
248 fn dyn_backend_as_soft_mut() {
249 let mut b = DynBackend::soft(10, 10);
250 let soft = b.as_soft_mut();
251 assert!(soft.is_some());
252 }
253}