Skip to content

Commit fd28676

Browse files
committed
wgpu: Fall back to software rendering if there are no GPU-backed WGPU adapters
Fixes #9164
1 parent 2ffb01c commit fd28676

File tree

8 files changed

+133
-53
lines changed

8 files changed

+133
-53
lines changed

internal/backends/winit/lib.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub enum WinitWindowEventResult {
5757
mod renderer {
5858
use std::sync::Arc;
5959

60-
use i_slint_core::{graphics::RequestedGraphicsAPI, platform::PlatformError};
60+
use i_slint_core::platform::PlatformError;
6161
use winit::event_loop::ActiveEventLoop;
6262

6363
pub trait WinitCompatibleRenderer {
@@ -74,7 +74,6 @@ mod renderer {
7474
&self,
7575
active_event_loop: &ActiveEventLoop,
7676
window_attributes: winit::window::WindowAttributes,
77-
requested_graphics_api: Option<RequestedGraphicsAPI>,
7877
) -> Result<Arc<winit::window::Window>, PlatformError>;
7978
}
8079

@@ -145,7 +144,11 @@ fn try_create_window_with_fallback_renderer(
145144
renderer::skia::WinitSkiaRenderer::new_suspended,
146145
#[cfg(feature = "renderer-femtovg-wgpu")]
147146
renderer::femtovg::WGPUFemtoVGRenderer::new_suspended,
148-
#[cfg(all(feature = "renderer-femtovg", supports_opengl))]
147+
#[cfg(all(
148+
feature = "renderer-femtovg",
149+
supports_opengl,
150+
not(feature = "renderer-femtovg-wgpu")
151+
))]
149152
renderer::femtovg::GlutinFemtoVGRenderer::new_suspended,
150153
#[cfg(feature = "renderer-software")]
151154
renderer::sw::WinitSoftwareRenderer::new_suspended,
@@ -156,7 +159,6 @@ fn try_create_window_with_fallback_renderer(
156159
shared_backend_data.clone(),
157160
renderer_factory(&shared_backend_data).ok()?,
158161
attrs.clone(),
159-
None,
160162
#[cfg(any(enable_accesskit, muda))]
161163
_proxy.clone(),
162164
#[cfg(all(muda, target_os = "macos"))]
@@ -363,7 +365,10 @@ impl BackendBuilder {
363365

364366
// Initialize the winit event loop and propagate errors if for example `DISPLAY` or `WAYLAND_DISPLAY` isn't set.
365367

366-
let shared_data = Rc::new(SharedBackendData::new(event_loop_builder)?);
368+
let shared_data = Rc::new(SharedBackendData::new(
369+
event_loop_builder,
370+
self.requested_graphics_api.clone(),
371+
)?);
367372

368373
let renderer_factory_fn = match (
369374
self.renderer_name.as_deref(),
@@ -373,7 +378,7 @@ impl BackendBuilder {
373378
(Some("gl"), maybe_graphics_api) | (Some("femtovg"), maybe_graphics_api) => {
374379
// If a graphics API was requested, double check that it's GL. FemtoVG doesn't support Metal, etc.
375380
if let Some(api) = maybe_graphics_api {
376-
i_slint_core::graphics::RequestedOpenGLVersion::try_from(api.clone())?;
381+
i_slint_core::graphics::RequestedOpenGLVersion::try_from(api)?;
377382
}
378383
renderer::femtovg::GlutinFemtoVGRenderer::new_suspended
379384
}
@@ -401,7 +406,7 @@ impl BackendBuilder {
401406
(Some("skia-opengl"), maybe_graphics_api @ _) => {
402407
// If a graphics API was requested, double check that it's GL. FemtoVG doesn't support Metal, etc.
403408
if let Some(api) = maybe_graphics_api {
404-
i_slint_core::graphics::RequestedOpenGLVersion::try_from(api.clone())?;
409+
i_slint_core::graphics::RequestedOpenGLVersion::try_from(api)?;
405410
}
406411
renderer::skia::WinitSkiaRenderer::new_opengl_suspended
407412
}
@@ -434,7 +439,7 @@ impl BackendBuilder {
434439
renderer::skia::WinitSkiaRenderer::factory_for_graphics_api(Some(_requested_graphics_api))?
435440
} else if #[cfg(all(feature = "renderer-femtovg", supports_opengl))] {
436441
// If a graphics API was requested, double check that it's GL. FemtoVG doesn't support Metal, etc.
437-
i_slint_core::graphics::RequestedOpenGLVersion::try_from(_requested_graphics_api.clone())?;
442+
i_slint_core::graphics::RequestedOpenGLVersion::try_from(_requested_graphics_api)?;
438443
renderer::femtovg::GlutinFemtoVGRenderer::new_suspended
439444
} else {
440445
return Err(format!("Graphics API use requested by the compile-time enabled renderers don't support that").into())
@@ -444,7 +449,6 @@ impl BackendBuilder {
444449
};
445450

446451
Ok(Backend {
447-
requested_graphics_api: self.requested_graphics_api,
448452
renderer_factory_fn,
449453
event_loop_state: Default::default(),
450454
window_attributes_hook: self.window_attributes_hook,
@@ -459,6 +463,7 @@ impl BackendBuilder {
459463
}
460464

461465
pub(crate) struct SharedBackendData {
466+
requested_graphics_api: Option<RequestedGraphicsAPI>,
462467
#[cfg(enable_skia_renderer)]
463468
skia_context: i_slint_renderer_skia::SkiaSharedContext,
464469
active_windows: RefCell<HashMap<winit::window::WindowId, Weak<WinitWindowAdapter>>>,
@@ -473,7 +478,10 @@ pub(crate) struct SharedBackendData {
473478
}
474479

475480
impl SharedBackendData {
476-
fn new(mut builder: EventLoopBuilder) -> Result<Self, PlatformError> {
481+
fn new(
482+
mut builder: EventLoopBuilder,
483+
requested_graphics_api: Option<RequestedGraphicsAPI>,
484+
) -> Result<Self, PlatformError> {
477485
#[cfg(not(target_arch = "wasm32"))]
478486
use raw_window_handle::HasDisplayHandle;
479487

@@ -526,6 +534,7 @@ impl SharedBackendData {
526534
.map_err(|display_err| PlatformError::OtherError(display_err.into()))?,
527535
);
528536
Ok(Self {
537+
requested_graphics_api,
529538
#[cfg(enable_skia_renderer)]
530539
skia_context: i_slint_renderer_skia::SkiaSharedContext::default(),
531540
active_windows: Default::default(),
@@ -589,7 +598,6 @@ impl SharedBackendData {
589598
/// slint::platform::set_platform(Box::new(Backend::new().unwrap()));
590599
/// ```
591600
pub struct Backend {
592-
requested_graphics_api: Option<RequestedGraphicsAPI>,
593601
renderer_factory_fn:
594602
fn(&Rc<SharedBackendData>) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError>,
595603
event_loop_state: RefCell<Option<crate::event_loop::EventLoopState>>,
@@ -684,7 +692,6 @@ impl i_slint_core::platform::Platform for Backend {
684692
self.shared_data.clone(),
685693
renderer,
686694
attrs.clone(),
687-
self.requested_graphics_api.clone(),
688695
#[cfg(any(enable_accesskit, muda))]
689696
self.shared_data.event_loop_proxy.clone(),
690697
#[cfg(all(muda, target_os = "macos"))]

internal/backends/winit/renderer/femtovg.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ mod glcontext;
2222
#[cfg(supports_opengl)]
2323
pub struct GlutinFemtoVGRenderer {
2424
renderer: FemtoVGRenderer<opengl::OpenGLBackend>,
25+
requested_graphics_api: Option<RequestedGraphicsAPI>,
2526
}
2627

2728
#[cfg(supports_opengl)]
2829
impl GlutinFemtoVGRenderer {
2930
pub fn new_suspended(
30-
_shared_backend_data: &Rc<crate::SharedBackendData>,
31+
shared_backend_data: &Rc<crate::SharedBackendData>,
3132
) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {
32-
Ok(Box::new(Self { renderer: FemtoVGRenderer::new_suspended() }))
33+
Ok(Box::new(Self {
34+
renderer: FemtoVGRenderer::new_suspended(),
35+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
36+
}))
3337
}
3438
}
3539

@@ -47,15 +51,12 @@ impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
4751
&self,
4852
active_event_loop: &ActiveEventLoop,
4953
window_attributes: winit::window::WindowAttributes,
50-
#[cfg_attr(target_arch = "wasm32", allow(unused_variables))] requested_graphics_api: Option<
51-
RequestedGraphicsAPI,
52-
>,
5354
) -> Result<Arc<winit::window::Window>, PlatformError> {
5455
#[cfg(not(target_arch = "wasm32"))]
5556
let (winit_window, opengl_context) = glcontext::OpenGLContext::new_context(
5657
window_attributes,
5758
active_event_loop,
58-
requested_graphics_api.map(TryInto::try_into).transpose()?,
59+
self.requested_graphics_api.as_ref().map(TryInto::try_into).transpose()?,
5960
)?;
6061

6162
#[cfg(target_arch = "wasm32")]
@@ -88,16 +89,23 @@ impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
8889
#[cfg(all(feature = "renderer-femtovg-wgpu", not(target_family = "wasm")))]
8990
pub struct WGPUFemtoVGRenderer {
9091
renderer: FemtoVGRenderer<i_slint_renderer_femtovg::wgpu::WGPUBackend>,
92+
requested_graphics_api: Option<RequestedGraphicsAPI>,
9193
}
9294

9395
#[cfg(all(feature = "renderer-femtovg-wgpu", not(target_family = "wasm")))]
9496
impl WGPUFemtoVGRenderer {
9597
pub fn new_suspended(
96-
_shared_backend_data: &Rc<crate::SharedBackendData>,
98+
shared_backend_data: &Rc<crate::SharedBackendData>,
9799
) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {
100+
if !i_slint_core::graphics::wgpu_26::any_wgpu26_adapters_with_gpu(
101+
shared_backend_data.requested_graphics_api.clone(),
102+
) {
103+
return Err(PlatformError::from("WGPU: No GPU adapters found"));
104+
}
98105
Ok(Box::new(Self {
99106
renderer: FemtoVGRenderer::<i_slint_renderer_femtovg::wgpu::WGPUBackend>::new_suspended(
100107
),
108+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
101109
}))
102110
}
103111
}
@@ -120,7 +128,6 @@ impl WinitCompatibleRenderer for WGPUFemtoVGRenderer {
120128
&self,
121129
active_event_loop: &ActiveEventLoop,
122130
window_attributes: winit::window::WindowAttributes,
123-
requested_graphics_api: Option<RequestedGraphicsAPI>,
124131
) -> Result<Arc<winit::window::Window>, PlatformError> {
125132
let winit_window = Arc::new(active_event_loop.create_window(window_attributes).map_err(
126133
|winit_os_error| {
@@ -136,7 +143,7 @@ impl WinitCompatibleRenderer for WGPUFemtoVGRenderer {
136143
self.renderer.set_window_handle(
137144
Box::new(winit_window.clone()),
138145
crate::winitwindowadapter::physical_size_to_slint(&size),
139-
requested_graphics_api,
146+
self.requested_graphics_api.clone(),
140147
)?;
141148

142149
Ok(winit_window)

internal/backends/winit/renderer/skia.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,58 +11,75 @@ use i_slint_renderer_skia::SkiaRenderer;
1111

1212
pub struct WinitSkiaRenderer {
1313
renderer: SkiaRenderer,
14+
requested_graphics_api: Option<RequestedGraphicsAPI>,
1415
}
1516

1617
impl WinitSkiaRenderer {
1718
pub fn new_suspended(
1819
shared_backend_data: &Rc<crate::SharedBackendData>,
1920
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
20-
Ok(Box::new(Self { renderer: SkiaRenderer::default(&shared_backend_data.skia_context) }))
21+
Ok(Box::new(Self {
22+
renderer: SkiaRenderer::default(&shared_backend_data.skia_context),
23+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
24+
}))
2125
}
2226

2327
#[cfg(not(target_os = "android"))]
2428
pub fn new_software_suspended(
2529
shared_backend_data: &Rc<crate::SharedBackendData>,
26-
) -> Box<dyn super::WinitCompatibleRenderer> {
27-
Box::new(Self {
30+
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
31+
Ok(Box::new(Self {
2832
renderer: SkiaRenderer::default_software(&shared_backend_data.skia_context),
29-
})
33+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
34+
}))
3035
}
3136

3237
#[cfg(not(ios_and_friends))]
3338
pub fn new_opengl_suspended(
3439
shared_backend_data: &Rc<crate::SharedBackendData>,
35-
) -> Box<dyn super::WinitCompatibleRenderer> {
36-
Box::new(Self { renderer: SkiaRenderer::default_opengl(&shared_backend_data.skia_context) })
40+
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
41+
Ok(Box::new(Self {
42+
renderer: SkiaRenderer::default_opengl(&shared_backend_data.skia_context),
43+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
44+
}))
3745
}
3846

3947
#[cfg(target_vendor = "apple")]
4048
pub fn new_metal_suspended(
4149
shared_backend_data: &Rc<crate::SharedBackendData>,
42-
) -> Box<dyn super::WinitCompatibleRenderer> {
43-
Box::new(Self { renderer: SkiaRenderer::default_metal(&shared_backend_data.skia_context) })
50+
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
51+
Ok(Box::new(Self {
52+
renderer: SkiaRenderer::default_metal(&shared_backend_data.skia_context),
53+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
54+
}))
4455
}
4556

4657
#[cfg(feature = "renderer-skia-vulkan")]
4758
pub fn new_vulkan_suspended(
4859
shared_backend_data: &Rc<crate::SharedBackendData>,
49-
) -> Box<dyn super::WinitCompatibleRenderer> {
50-
Box::new(Self { renderer: SkiaRenderer::default_vulkan(&shared_backend_data.skia_context) })
60+
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
61+
Ok(Box::new(Self {
62+
renderer: SkiaRenderer::default_vulkan(&shared_backend_data.skia_context),
63+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
64+
}))
5165
}
5266

5367
#[cfg(target_family = "windows")]
5468
pub fn new_direct3d_suspended(
5569
shared_backend_data: &Rc<crate::SharedBackendData>,
56-
) -> Box<dyn super::WinitCompatibleRenderer> {
57-
Box::new(Self {
70+
) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {
71+
Ok(Box::new(Self {
5872
renderer: SkiaRenderer::default_direct3d(&shared_backend_data.skia_context),
59-
})
73+
requested_graphics_api: shared_backend_data.requested_graphics_api.clone(),
74+
}))
6075
}
6176

6277
pub fn factory_for_graphics_api(
6378
requested_graphics_api: Option<&RequestedGraphicsAPI>,
6479
) -> Result<
65-
fn(&Rc<crate::SharedBackendData>) -> Box<dyn crate::WinitCompatibleRenderer>,
80+
fn(
81+
&Rc<crate::SharedBackendData>,
82+
) -> Result<Box<dyn crate::WinitCompatibleRenderer>, PlatformError>,
6683
PlatformError,
6784
> {
6885
match requested_graphics_api {
@@ -130,7 +147,6 @@ impl super::WinitCompatibleRenderer for WinitSkiaRenderer {
130147
&self,
131148
active_event_loop: &winit::event_loop::ActiveEventLoop,
132149
window_attributes: winit::window::WindowAttributes,
133-
requested_graphics_api: Option<RequestedGraphicsAPI>,
134150
) -> Result<Arc<winit::window::Window>, PlatformError> {
135151
let winit_window = Arc::new(active_event_loop.create_window(window_attributes).map_err(
136152
|winit_os_error| {
@@ -147,7 +163,7 @@ impl super::WinitCompatibleRenderer for WinitSkiaRenderer {
147163
winit_window.clone(),
148164
winit_window.clone(),
149165
physical_size_to_slint(&size),
150-
requested_graphics_api,
166+
self.requested_graphics_api.clone(),
151167
)?;
152168

153169
self.renderer.set_pre_present_callback(Some(Box::new({

internal/backends/winit/renderer/sw.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
66
use core::num::NonZeroU32;
77
use core::ops::DerefMut;
8+
use i_slint_core::graphics::Rgb8Pixel;
89
use i_slint_core::platform::PlatformError;
910
pub use i_slint_core::software_renderer::SoftwareRenderer;
1011
use i_slint_core::software_renderer::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel};
11-
use i_slint_core::{graphics::RequestedGraphicsAPI, graphics::Rgb8Pixel};
1212
use std::cell::RefCell;
1313
use std::rc::Rc;
1414
use std::sync::Arc;
@@ -180,7 +180,6 @@ impl super::WinitCompatibleRenderer for WinitSoftwareRenderer {
180180
&self,
181181
active_event_loop: &ActiveEventLoop,
182182
window_attributes: winit::window::WindowAttributes,
183-
_requested_graphics_api: Option<RequestedGraphicsAPI>,
184183
) -> Result<Arc<winit::window::Window>, PlatformError> {
185184
let winit_window =
186185
active_event_loop.create_window(window_attributes).map_err(|winit_os_error| {

internal/backends/winit/winitwindowadapter.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use corelib::platform::{PlatformError, WindowEvent};
4343
use corelib::window::{WindowAdapter, WindowAdapterInternal, WindowInner};
4444
use corelib::Property;
4545
use corelib::{graphics::*, Coord};
46-
use i_slint_core::{self as corelib, graphics::RequestedGraphicsAPI};
46+
use i_slint_core::{self as corelib};
4747
use std::cell::OnceCell;
4848
#[cfg(any(enable_accesskit, muda))]
4949
use winit::event_loop::EventLoopProxy;
@@ -323,7 +323,6 @@ pub struct WinitWindowAdapter {
323323
fullscreen: Cell<bool>,
324324

325325
pub(crate) renderer: Box<dyn WinitCompatibleRenderer>,
326-
requested_graphics_api: Option<RequestedGraphicsAPI>,
327326
/// We cache the size because winit_window.inner_size() can return different value between calls (eg, on X11)
328327
/// And we wan see the newer value before the Resized event was received, leading to inconsistencies
329328
size: Cell<PhysicalSize>,
@@ -382,7 +381,6 @@ impl WinitWindowAdapter {
382381
shared_backend_data: Rc<SharedBackendData>,
383382
renderer: Box<dyn WinitCompatibleRenderer>,
384383
window_attributes: winit::window::WindowAttributes,
385-
requested_graphics_api: Option<RequestedGraphicsAPI>,
386384
#[cfg(any(enable_accesskit, muda))] proxy: EventLoopProxy<SlintEvent>,
387385
#[cfg(all(muda, target_os = "macos"))] muda_enable_default_menu_bar: bool,
388386
) -> Rc<Self> {
@@ -405,7 +403,6 @@ impl WinitWindowAdapter {
405403
has_explicit_size: Default::default(),
406404
pending_resize_event_after_show: Default::default(),
407405
renderer,
408-
requested_graphics_api,
409406
#[cfg(target_arch = "wasm32")]
410407
virtual_keyboard_helper: Default::default(),
411408
#[cfg(any(enable_accesskit, muda))]
@@ -484,11 +481,7 @@ impl WinitWindowAdapter {
484481
window_attributes = window_attributes.with_transparent(false);
485482
}
486483

487-
let winit_window = self.renderer.resume(
488-
active_event_loop,
489-
window_attributes,
490-
self.requested_graphics_api.clone(),
491-
)?;
484+
let winit_window = self.renderer.resume(active_event_loop, window_attributes)?;
492485

493486
let scale_factor =
494487
overriding_scale_factor.unwrap_or_else(|| winit_window.scale_factor() as f32);

internal/core/graphics.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,14 @@ pub enum RequestedGraphicsAPI {
195195
WGPU26(wgpu_26::api::WGPUConfiguration),
196196
}
197197

198-
impl TryFrom<RequestedGraphicsAPI> for RequestedOpenGLVersion {
198+
impl TryFrom<&RequestedGraphicsAPI> for RequestedOpenGLVersion {
199199
type Error = PlatformError;
200200

201-
fn try_from(requested_graphics_api: RequestedGraphicsAPI) -> Result<Self, Self::Error> {
201+
fn try_from(requested_graphics_api: &RequestedGraphicsAPI) -> Result<Self, Self::Error> {
202202
match requested_graphics_api {
203-
RequestedGraphicsAPI::OpenGL(requested_open_glversion) => Ok(requested_open_glversion),
203+
RequestedGraphicsAPI::OpenGL(requested_open_glversion) => {
204+
Ok(requested_open_glversion.clone())
205+
}
204206
RequestedGraphicsAPI::Metal => {
205207
Err("Metal rendering is not supported with an OpenGL renderer".into())
206208
}

0 commit comments

Comments
 (0)