emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
21.69k stars 1.56k forks source link

requirement for users to select wgpu features is undocumented & resulting errors hard to interpret #4885

Open kametsuu opened 1 month ago

kametsuu commented 1 month ago

Describe the bug DirectX12 doesn't work with eframe and errors with error:

[2024-07-28T19:05:15Z ERROR eframe::native::run] Exiting because of error: WGPU error: Failed to create surface for any enabled backend: {} during event Resumed
Error: Wgpu(CreateSurfaceError(CreateSurfaceError { inner: Hal(FailedToCreateSurfaceForAnyBackend({})) }))
error: process didn't exit successfully: `target\debug\dx12eframe.exe` (exit code: 1)

Here is minimal example:

Cargo.toml

[package]
name = "dx12eframe"
version = "0.1.0"
edition = "2021"

[dependencies]
eframe = { version = "0.28.0", features = ["wgpu"] }
env_logger = "0.11.5"

main.rs

use eframe::egui;

fn main() -> Result<(), eframe::Error> {
    env_logger::init();

    let native_options = eframe::NativeOptions {
        renderer: eframe::Renderer::Wgpu,
        wgpu_options: eframe::egui_wgpu::WgpuConfiguration {
            supported_backends: eframe::wgpu::Backends::DX12,
            ..Default::default()
        },
        ..Default::default()
    };

    eframe::run_simple_native("Hello world", native_options, move |ctx, _frame| {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("Hello world");
        });
    })
}

It's only happening for me while using DX12 (GL and Vulkan works fine). But when I use only wgpu with winit (exactly code from here) it works, so I guess it must be a bug in egui/eframe (that's why I post issue here).

Desktop:

If there's anything else you need me to provide or check then just say :)

kametsuu commented 1 month ago

Okay, I found what the problem was. Egui has all the default feature flags for crate wgpu disabled, and in that case only Vulkan and GLES backends are available on Windows (and Linux & Android).

So in order to get DX12 working, I had to enable the default feature flags for wgpu in Cargo.toml:

[package]
name = "dx12eframe"
version = "0.1.0"
edition = "2021"

[dependencies]
eframe = { git = "https://github.com/emilk/egui", branch = "master", features = [
    "wgpu",
] }
wgpu = { version = "22.0.0", default-features = true, features = [
    "fragile-send-sync-non-atomic-wasm",
] }
env_logger = "0.11.5"

I think this should be written somewhere in the documentation, because this behavior (for me, a newcomer to Rust) was very unclear and I spent so much time wondering what it could be, only to find out that it was just an unenabled feature flag.

Alternatively, I want to propose an approach that is used in regex Rust crate in which they solve it by simply re-exporting the dependency's feature flags of the unicode library, which is used by their underlying regex-syntax library thus allowing you to control the features by directly setting the feature flags for the regex crate. See: regex's Cargo.toml and regex-syntax's Cargo.toml

9SMTM6 commented 6 days ago

I think it should be possible to panic if you pass a backend to wgpu that isn't compiled in. Because actually the information is all there: WGPU error: Failed to create surface for any enabled backend: {}. There is no enabled backend available. I'm honestly a bit surprised that wgpu allows you to reference these backends (eframe::wgpu is a re-export of wgpu IIRC).

But with a panic its harder to miss, and doesn't need documentation.

emilk commented 5 days ago

PTAL @Wumpf

Wumpf commented 4 days ago

Documenting the behavior would be good, yes! Resurfacing all features though I'm quite skeptical about since wgpu just has too many and too complex features, see https://docs.rs/wgpu/latest/wgpu/#feature-flags

I think it should be possible to panic if you pass a backend to wgpu that isn't compiled in.

Hmm yeah we should have some runtime error (would be good if it doesn't need to be panic and can be more graceful). I added wgpu::Instance::enabled_backend_features not too long ago to do this sort of check at runtime. I'm wondering how the wgpu api could do this sort of thing better. It's already sorta correct by telling users that there's no adapter, but I wonder if it could be more explicit about the why there is no adapter