Skip to content

Demos and examples: show alert on webgl init failure - #12771

Open
the-argus wants to merge 4 commits into
slint-ui:masterfrom
the-argus:webgl-context-failure-popup
Open

Demos and examples: show alert on webgl init failure#12771
the-argus wants to merge 4 commits into
slint-ui:masterfrom
the-argus:webgl-context-failure-popup

Conversation

@the-argus

@the-argus the-argus commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This PR addresses #896 and makes it so that all examples have an obvious error popup if a platform error (such as webgl not loading) happens at startup.

Previously, only the slide puzzle example had this feature. However, it was only able to observe that the main wasm module had panicked and could not get its error message (on panic, the error displayed said something like "unreachable executed"). There was also some unused stuff to return any error from MainWindow::run() out of main(). While that would successfully be converted to an exception and be displayed in an alert, it would never happen on web because run() just throws a js exception and never returns: https://docs.rs/winit/latest/winit/event_loop/struct.EventLoop.html#method.run_app (called here). The documentation on run_app() suggests using EventLoopExtWebSys::spawn_app() instead but I do not see an easy way to migrate to that.

I considered making it so that any exit of the event loop would throw an exception + display an error, but I am not certain that every error should be displayed to the user in that way, so I just kept it in the scope of the issue and just made errors returned from create_inactive_windows() be propagated into exceptions + alerts.

I also reverted the changes related to returning PlatformError from main since unwrapping those is fine/consistent with other examples and it was unused on web anyways.

Opening a demo in a browser with webgl disabled:
Screenshot 2026-08-03 at 3 34 38 PM

After pressing OK:
Screenshot 2026-08-03 at 3 34 52 PM

I also made a slight change to how the "Slint requires WebGL to be enabled in your browser" warning text appears in the canvas window, since it was getting cut off for me when viewing things like the home automation demo. Previously it looked like this:

Screenshot 2026-08-03 at 10 51 29 AM

@the-argus

the-argus commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Hm, I also observe a different issue here. Looking closer at specifically the gallery example, the alert is not appearing because of webGL failure, it appears regardless, because the index.html seems to expect subdirectories for different styles, fluent, material, etc, which are not present. I believe heard something about support for some styles being dropped so I will not touch that for now.

@tronical tronical left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Rust panic to propagate an error seems counter-intuitive. Why can't we propagate the error via Result to JavaScript?

Comment thread internal/core/api.rs
Comment thread examples/slide_puzzle/main.rs Outdated

#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
pub fn main() -> Result<(), slint::PlatformError> {
pub fn main() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems counter-intuitive. If wasm-bindgen doesn't support Result<> for main, maybe that's what needs fixing - but at least I think it's worth investigating.

@the-argus the-argus Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, it is fundamental to the way doing an event driven browser app works, because the browser controls the event loop we have to yield from main in some way or another before the app can even start, since main's job is just to set up the callbacks for the browser to call, not to actually drive things. So failure while the app is running will happen in a place where our main() isn't even in the call stack.

So to be clear, wasm-bindgen does support returning result from main, its just that the webgl error specifically will not be propagated this way.

Now that I look closer, I should probably have kept this result return for the examples, because that would work as intended for errors that occur before the event loop starts, specifically MainWindow::new(). But it would not help the WebGL error since that happens inside of an event handler.

I think in order for us to use Result to propagate this error, winit would have to support returning Result from the trait functions of ApplicationHandler and have those be converted to js exceptions, as returning a result from main() currently does.

Another option which would be similar but leave more rust error handling control flow intact would be to throw the exception in exiting() handler, since that gets called when the browser is closing down the event loop anyways. But then there would (probably?) need to be a mechanism to decide whether a given error warrants an alert popup to the user.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I look closer, I should probably have kept this result return for the examples, because that would work as intended for errors that occur before the event loop starts, specifically MainWindow::new(). But it would not help the WebGL error since that happens inside of an event handler.

I agree.

I think in order for us to use Result to propagate this error, winit would have to support returning Result from the trait functions of ApplicationHandler and have those be converted to js exceptions, as returning a result from main() currently does.

Right, this isn't possible. Even if we used spawn.

Fundamentally we should try to detect WebGL compatibility problems as early as possible to fit better into our flow of error handling. But any errors after that will either way leave the page useless and the best we can probably do is show an alert or so (we can trigger that).

@tronical

tronical commented Aug 5, 2026

Copy link
Copy Markdown
Member

Maybe a different way of looking at this: If we want to detect that the browser doesn't support the absolute minimum requirements we need, then we should do that check as early as possible so that if its into our Result<> API. I think in practice that means performing this checking early on in the winit backend initialisation. Perhaps that can delegate to the renderer (just for wasm).

@the-argus

Copy link
Copy Markdown
Contributor Author

I see, I will return Result from everything and then see about detecting this error earlier.

This improves error messages on wasm for errors that occur before the
event loop starts (ie. before we yield out of main).
If the example returns an error from main, this will display a popup
with the error's message. If the module panics it will also display a
popup but the error message will not be helpful, refer to the console in
debug mode (thanks to console_error_panic_hook) in that case.

This was already the case for the slide puzzle example and has just been
copied to other examples and demos.
@the-argus
the-argus force-pushed the webgl-context-failure-popup branch from a884621 to d5abbc8 Compare August 5, 2026 18:20
We don't have a way to return errors out of event handlers in wasm
besides panics and exceptions, but we want to display an error message
on the event of webgl initialization failure. To get around this, we can
create the webgl context when initializing the window, and recognize
failures there.
@the-argus
the-argus force-pushed the webgl-context-failure-popup branch from d5abbc8 to 590a550 Compare August 5, 2026 18:31
@the-argus

Copy link
Copy Markdown
Contributor Author

@tronical AFAICT, there is not really any check for webgl support as conclusive as actually trying to create the context, so I've changed things to do that early, in new_suspended(). The canvas will store it and then return it to femtovg later.

But this solution isn't perfect since normally we let femtovg decide the parameters for the context creation, we have to replicate those on our end and potentially keep them in sync if they were to change (though I doubt that will happen to any meaningful extent).

Additionally, returning an error from new_suspended means that the renderer selection will try to fall back to software and not display the error message. My solution to this was just to disable software renderer on web since it doesn't appear to be a valid fallback for web anyways:

  panicked at .../slint/internal/renderers/software/lib.rs:2459:21:
  not implemented: The image cannot be rendered

So only femtovg is considered and then the webgl error gets returned and displayed as an alert.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants