gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.55k stars 918 forks source link

Option::unwrap in wgpu_hal on nixos #6165

Open VoreckLukas opened 2 months ago

VoreckLukas commented 2 months ago

So I'm using nixos and building an iced application. So far so good, everything works, i got all libraries set up. Then I pull in iced_aw and i start getting the error below and can't for the live of me figure out which library it's missing

thread 'main' panicked at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:88:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

with RUST_BACKTRACE

❯ RUST_BACKTRACE=1 target/debug/chip8-iced 
thread 'main' panicked at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:88:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic
   3: core::option::unwrap_failed
   4: core::option::Option<T>::unwrap
             at /build/rustc-1.77.2-src/library/core/src/option.rs:931:21
   5: <wgpu_hal::gles::egl::Instance as wgpu_hal::Instance<wgpu_hal::gles::Api>>::init
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:31
   6: wgpu_core::instance::Instance::new::init
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/instance.rs:86:32
   7: wgpu_core::instance::Instance::new
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/instance.rs:115:17
   8: wgpu_core::global::Global<G>::new
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/global.rs:59:23
   9: <wgpu::backend::wgpu_core::ContextWgpuCore as wgpu::context::Context>::init
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.4/src/backend/wgpu_core.rs:513:14
  10: wgpu::Instance::new
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.4/src/lib.rs:1833:36
  11: iced_wgpu::window::compositor::Compositor::request::{{closure}}
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_wgpu-0.12.1/src/window/compositor.rs:29:24
  12: futures_executor::local_pool::block_on::{{closure}}
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:317:23
  13: futures_executor::local_pool::run_executor::{{closure}}
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:90:37
  14: std::thread::local::LocalKey<T>::try_with
             at /build/rustc-1.77.2-src/library/std/src/thread/local.rs:286:16
  15: std::thread::local::LocalKey<T>::with
             at /build/rustc-1.77.2-src/library/std/src/thread/local.rs:262:9
  16: futures_executor::local_pool::run_executor
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:86:5
  17: futures_executor::local_pool::block_on
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:317:5
  18: iced_wgpu::window::compositor::new
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_wgpu-0.12.1/src/window/compositor.rs:159:22
  19: iced_renderer::compositor::Candidate::build
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_renderer-0.12.1/src/compositor.rs:247:34
  20: <iced_renderer::compositor::Compositor as iced_graphics::compositor::Compositor>::new
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_renderer-0.12.1/src/compositor.rs:35:19
  21: iced_winit::application::run
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_winit-0.12.2/src/application.rs:191:22
  22: iced::application::Application::run
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced-0.12.1/src/application.rs:208:12
  23: iced::sandbox::Sandbox::run
             at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced-0.12.1/src/sandbox.rs:153:9
  24: chip8_iced::main
             at ./chip8-iced/src/main.rs:11:5
  25: core::ops::function::FnOnce::call_once
             at /build/rustc-1.77.2-src/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

And with full backtrace

 ❯ RUST_BACKTRACE=full target/debug/chip8-iced 
thread 'main' panicked at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:88:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0:     0x56006e427037 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h4886110ae7835fd2
   1:     0x56006e45bfa0 - core::fmt::write::h6fab83f0f5bc0c8f
   2:     0x56006e43f885 - std::io::Write::write_fmt::h64824cb874054607
   3:     0x56006e426e04 - std::sys_common::backtrace::print::hb8fea9d041077138
   4:     0x56006e427977 - std::panicking::default_hook::{{closure}}::hc60f0f690c67943c
   5:     0x56006e4276d7 - std::panicking::default_hook::h56281bcc5d6e2f17
   6:     0x56006e427ee8 - std::panicking::rust_panic_with_hook::hd61e30fe5971d187
   7:     0x56006e427d8e - std::panicking::begin_panic_handler::{{closure}}::h95d2684e28f89fd2
   8:     0x56006e427266 - std::sys_common::backtrace::__rust_end_short_backtrace::h48780d898316fff8
   9:     0x56006e427b14 - rust_begin_unwind
  10:     0x56006ce19aa5 - core::panicking::panic_fmt::hdb89b5c14a056cec
  11:     0x56006ce19b63 - core::panicking::panic::h0e6608ccd7056721
  12:     0x56006ce1a1a6 - core::option::unwrap_failed::h42b5e841a9c29a32
  13:     0x56006e026845 - core::option::Option<T>::unwrap::hded2709bd8630a96
                               at /build/rustc-1.77.2-src/library/core/src/option.rs:931:21
  14:     0x56006e026845 - <wgpu_hal::gles::egl::Instance as wgpu_hal::Instance<wgpu_hal::gles::Api>>::init::h150ad6d6bb0c05d4
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:31
  15:     0x56006df31fd0 - wgpu_core::instance::Instance::new::init::h70c041f536e033fd
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/instance.rs:86:32
  16:     0x56006df3139b - wgpu_core::instance::Instance::new::h99a8f9918d86ae8c
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/instance.rs:115:17
  17:     0x56006de835fe - wgpu_core::global::Global<G>::new::h9cf7648d0d7c0260
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.4/src/global.rs:59:23
  18:     0x56006dc7ee3b - <wgpu::backend::wgpu_core::ContextWgpuCore as wgpu::context::Context>::init::h3fdcbe4bc89270e4
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.4/src/backend/wgpu_core.rs:513:14
  19:     0x56006dca7af8 - wgpu::Instance::new::hf4317dbc8b7b1984
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.4/src/lib.rs:1833:36
  20:     0x56006cf84201 - iced_wgpu::window::compositor::Compositor::request::{{closure}}::h8eaf166c5e6c5e29
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_wgpu-0.12.1/src/window/compositor.rs:29:24
  21:     0x56006cf723f8 - futures_executor::local_pool::block_on::{{closure}}::h944faef2f58d6edc
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:317:23
  22:     0x56006cf72256 - futures_executor::local_pool::run_executor::{{closure}}::hd30626d1802c86a9
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:90:37
  23:     0x56006cf2b61b - std::thread::local::LocalKey<T>::try_with::h2acb57e0911de025
                               at /build/rustc-1.77.2-src/library/std/src/thread/local.rs:286:16
  24:     0x56006cf2b4bb - std::thread::local::LocalKey<T>::with::h4b3dee4611e88984
                               at /build/rustc-1.77.2-src/library/std/src/thread/local.rs:262:9
  25:     0x56006cf72194 - futures_executor::local_pool::run_executor::h342d9faa48fc608d
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:86:5
  26:     0x56006cf7237a - futures_executor::local_pool::block_on::hc0e617a0d773a824
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-executor-0.3.30/src/local_pool.rs:317:5
  27:     0x56006cf87504 - iced_wgpu::window::compositor::new::h2c8c917798a8a837
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_wgpu-0.12.1/src/window/compositor.rs:159:22
  28:     0x56006cf5b1f0 - iced_renderer::compositor::Candidate::build::hdc8efa20b4c15d02
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_renderer-0.12.1/src/compositor.rs:247:34
  29:     0x56006cf5b9b4 - <iced_renderer::compositor::Compositor as iced_graphics::compositor::Compositor>::new::h1e024a1bb90087a6
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_renderer-0.12.1/src/compositor.rs:35:19
  30:     0x56006cf82388 - iced_winit::application::run::h60cf60612157f590
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced_winit-0.12.2/src/application.rs:191:22
  31:     0x56006cf4c0cf - iced::application::Application::run::hdfb9326dfe9cfc3c
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced-0.12.1/src/application.rs:208:12
  32:     0x56006cf4c31d - iced::sandbox::Sandbox::run::h62bd6085464ab4ad
                               at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/iced-0.12.1/src/sandbox.rs:153:9
  33:     0x56006cf20168 - chip8_iced::main::h6ec256546d329b67
                               at /home/lukas/Project/chip8/chip8-iced/src/main.rs:11:5
  34:     0x56006ce901f2 - core::ops::function::FnOnce::call_once::h66777604bdbe4352
                               at /build/rustc-1.77.2-src/library/core/src/ops/function.rs:250:5
  35:     0x56006ce3fe95 - std::sys_common::backtrace::__rust_begin_short_backtrace::hd59d9815f3064331
                               at /build/rustc-1.77.2-src/library/std/src/sys_common/backtrace.rs:155:18
  36:     0x56006cf76646 - std::rt::lang_start::{{closure}}::hce593592ff2ab62e
                               at /build/rustc-1.77.2-src/library/std/src/rt.rs:166:18
  37:     0x56006e427a14 - std::panicking::try::ha86251cf5daa9bea
  38:     0x56006e41818b - std::rt::lang_start_internal::ha6a51778162f8d22
  39:     0x56006cf7661a - std::rt::lang_start::h2b2f3d02b5847fbd
                               at /build/rustc-1.77.2-src/library/std/src/rt.rs:165:17
  40:     0x56006cf2064e - main
  41:     0x7f2eb181e10e - __libc_start_call_main
  42:     0x7f2eb181e1c9 - __libc_start_main@@GLIBC_2.34
  43:     0x56006ce1a4e5 - _start
  44:                0x0 - <unknown>
teoxoy commented 2 months ago

This is the unwrap.

https://github.com/gfx-rs/wgpu/blob/db9fb2ef354af7c1da58e4210d6b9cb5c38d5cb8/wgpu-hal/src/gles/egl.rs#L789

khronos_egl maps EGL_NO_DISPLAY to None for eglGetDisplay.

I think we should error instead of panicking.

VoreckLukas commented 2 months ago

Still, do you have any idea why that could be None and what lib I am missing?

teoxoy commented 2 months ago

Maybe the DISPLAY env var is not set? I'm not too familiar with this mechanism. I'd look online for "eglGetDisplay(EGL_DEFAULT_DISPLAY) returns EGL_NO_DISPLAY".

VoreckLukas commented 2 months ago

Okay here comes the weird thing: I Just created a little test program

fn main() {
    unsafe {
        let egl = dbg!(khronos_egl::DynamicInstance::<khronos_egl::EGL1_4>::load_required()).unwrap();
        dbg!(egl.get_display(khronos_egl::DEFAULT_DISPLAY)).unwrap();
    }
}

Which if I'm correct should produce the same error, right? Wrong

 ❯ cargo run -p testing
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/testing`
[testing/src/main.rs:3:19] khronos_egl::DynamicInstance::<khronos_egl::EGL1_4>::load_required() = Ok(
    Instance(Dynamic(Library@0x55aa58a70c10)),
)
[testing/src/main.rs:5:9] egl.get_display(khronos_egl::DEFAULT_DISPLAY) = Some(
    Display(
        0x000055aa58a7d480,
    ),
)
VoreckLukas commented 2 months ago

Since I just saw there are log statements, I quickly added env_logger

 ❯ RUST_LOG="trace" target/debug/chip8-iced 
[2024-08-27T14:25:51Z DEBUG sctk] Bound new global [47] wl_output v4
[2024-08-27T14:25:51Z DEBUG sctk] Bound new global [9] zxdg_output_manager_v1 v3
[2024-08-27T14:25:51Z DEBUG sctk] Bound new global [1] wl_seat v7
[2024-08-27T14:25:51Z DEBUG sctk] Bound new global [10] wp_cursor_shape_manager_v1 v1
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Argb8888
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Xrgb8888
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Argb2101010
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Xrgb2101010
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Abgr2101010
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Xbgr2101010
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Abgr8888
[2024-08-27T14:25:51Z DEBUG sctk] supported wl_shm format Xbgr8888
[2024-08-27T14:25:51Z TRACE calloop::loop_logic] [calloop] Inserting new source #0
[2024-08-27T14:25:51Z TRACE calloop::loop_logic] [calloop] Inserting new source #1
[2024-08-27T14:25:51Z TRACE calloop::loop_logic] [calloop] Inserting new source #2
[2024-08-27T14:25:51Z DEBUG iced_winit::application] Window builder: WindowBuilder {
        window: WindowAttributes {
            inner_size: Some(
                Logical(
                    LogicalSize {
                        width: 1024.0,
                        height: 768.0,
                    },
                ),
            ),
            min_inner_size: None,
            max_inner_size: None,
            position: None,
            resizable: true,
            enabled_buttons: WindowButtons(
                CLOSE | MINIMIZE | MAXIMIZE,
            ),
            title: "Chip8",
            maximized: false,
            visible: false,
            transparent: false,
            blur: false,
            decorations: true,
            window_icon: None,
            preferred_theme: None,
            resize_increments: None,
            content_protected: false,
            window_level: Normal,
            active: true,
            parent_window: SendSyncWrapper(
                None,
            ),
            fullscreen: SendSyncWrapper(
                None,
            ),
        },
    }
[2024-08-27T14:25:51Z DEBUG wgpu_core::instance] Instance::new: failed to create Vulkan backend: InstanceError { message: "missing Vulkan entry points", source: Some(LibraryLoadFailure(DlOpen { desc: "libvulkan.so.1: cannot open shared object file: No such file or directory" })) }
[2024-08-27T14:25:51Z DEBUG wgpu_hal::gles::egl] Client extensions: []
[2024-08-27T14:25:51Z WARN  wgpu_hal::gles::egl] EGL_MESA_platform_surfaceless not available. Using default platform
thread 'main' panicked at /home/lukas/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-hal-0.19.5/src/gles/egl.rs:789:88:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
VoreckLukas commented 2 months ago

Okay i did some more testing with the logging. I ran it via steam-run (a magic nixos tool that loads in libraries at runtime, but itsnt suited for packaging applications, neither is it good when i want to do cargo run) Then it works and the logs sho me it's going into the wayland platform path while the above is crashing in the default platform path. So either the wayland library is none or the egl1_5 is none. So i threw together a minimal test

use std::{ptr, os::raw};

fn main() {
    unsafe {
        let egl = khronos_egl::DynamicInstance::<khronos_egl::EGL1_4>::load_required();
        let egl = egl.unwrap();
        let client_extensions = egl.query_string(None, khronos_egl::EXTENSIONS);

        let client_ext_str = match client_extensions {
            Ok(ext) => ext.to_string_lossy().into_owned(),
            Err(_) => String::new(),
        };
        println!(
            "Client extensions: {:#?}",
            client_ext_str.split_whitespace().collect::<Vec<_>>()
        );
        let egl1_5 = egl.upcast::<khronos_egl::EGL1_5>();
        dbg!(egl1_5);
        let wayland_library = if client_ext_str.contains("EGL_EXT_platform_wayland") {
            test_wayland_display()
        } else {
            None
        };
        dbg!(wayland_library);
    }
}

fn test_wayland_display() -> Option<DisplayOwner> {
    /* We try to connect and disconnect here to simply ensure there
     * is an active wayland display available.
     */
    let library = unsafe {
        let client_library = find_library(&["libwayland-client.so.0", "libwayland-client.so"])?;
        let wl_display_connect: libloading::Symbol<WlDisplayConnectFun> =
            client_library.get(b"wl_display_connect").unwrap();
        let wl_display_disconnect: libloading::Symbol<WlDisplayDisconnectFun> =
            client_library.get(b"wl_display_disconnect").unwrap();
        let display = ptr::NonNull::new(wl_display_connect(ptr::null()))?;
        wl_display_disconnect(display.as_ptr());
        find_library(&["libwayland-egl.so.1", "libwayland-egl.so"])?
    };
    Some(DisplayOwner {
        library,
        display: DisplayRef::Wayland,
    })
}

#[derive(Debug)]
struct DisplayOwner {
    library: libloading::Library,
    display: DisplayRef,
}

unsafe fn find_library(paths: &[&str]) -> Option<libloading::Library> {
    for path in paths {
        match unsafe { libloading::Library::new(path) } {
            Ok(lib) => return Some(lib),
            _ => continue,
        };
    }
    None
}

type WlDisplayConnectFun =
    unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void;

type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const raw::c_void);

#[derive(Debug)]
enum DisplayRef {
    X11(ptr::NonNull<raw::c_void>),
    Wayland,
}

Which includes all relevant code from the file you linked that sets those two variables. running it in the exact same environment as my binary that crashes gives me this


Client extensions: [
    "EGL_EXT_device_base",
    "EGL_EXT_device_enumeration",
    "EGL_EXT_device_query",
    "EGL_EXT_platform_base",
    "EGL_KHR_client_get_all_proc_addresses",
    "EGL_EXT_client_extensions",
    "EGL_KHR_debug",
    "EGL_EXT_platform_device",
    "EGL_EXT_explicit_device",
    "EGL_EXT_platform_wayland",
    "EGL_KHR_platform_wayland",
    "EGL_EXT_platform_x11",
    "EGL_KHR_platform_x11",
    "EGL_EXT_platform_xcb",
    "EGL_MESA_platform_gbm",
    "EGL_KHR_platform_gbm",
    "EGL_MESA_platform_surfaceless",
]
[testing/src/main.rs:18:9] egl1_5 = Some(
    Instance(Dynamic(Library@0x559982da5c10)),
)
[testing/src/main.rs:24:9] wayland_library = Some(
    DisplayOwner {
        library: Library@0x559982db30f0,
        display: Wayland,
    },
)```
teoxoy commented 2 months ago

The list of client extensions is empty here https://github.com/gfx-rs/wgpu/issues/6165#issuecomment-2312727001, but in https://github.com/gfx-rs/wgpu/issues/6165#issuecomment-2312822413 it's not.

Just to confirm, when using steam-run will the list of client extensions always be populated? And with cargo run it will be empty?

If so, it sounds like an env issue and it would be worth figuring out what steam-run does.

On our end, I think we shouldn't unwrap there and instead report that there is no display available.

VoreckLukas commented 2 months ago

Just to confirm, when using steam-run will the list of client extensions always be populated? And with cargo run it will be empty?

Correct. but the second example is still a normal cargo run, but with the minimal test I threw together, no cargo required

By now I found out my issue it was a driver mismatch but it's weird that it affects one project but not the other besides both running in the same environment with the same command

On our end, I think we shouldn't unwrap there and instead report that there is no display available.

My issue is solved but I'll leave this open if you want to track that change

EdupugantiAkhil commented 2 months ago

@VoreckLukas, would you mind sharing the config/fix if you were able to get it to run without steam-run BTW thanks for sharing the workaround.

VoreckLukas commented 2 months ago

@VoreckLukas, would you mind sharing the config/fix if you were able to get it to run without steam-run BTW thanks for sharing the workaround.

The key is to keep your flake at the same version of nixpkgs as the rest of your system