fix: wgpu panics

This commit is contained in:
Ashley Wulber 2026-02-04 15:37:28 -05:00
parent 37572b76f9
commit c40264a6ed
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820

View file

@ -1,4 +1,6 @@
//! Connect a window with a renderer. //! Connect a window with a renderer.
use wgpu::Backends;
use crate::core::Color; use crate::core::Color;
use crate::graphics::color; use crate::graphics::color;
use crate::graphics::compositor; use crate::graphics::compositor;
@ -53,7 +55,7 @@ impl Compositor {
/// Requests a new [`Compositor`] with the given [`Settings`]. /// Requests a new [`Compositor`] with the given [`Settings`].
/// ///
/// Returns `None` if no compatible graphics adapter could be found. /// Returns `None` if no compatible graphics adapter could be found.
pub async fn request<W: compositor::Window>( pub async fn request<W: compositor::Window + Clone>(
settings: Settings, settings: Settings,
compatible_window: Option<W>, compatible_window: Option<W>,
shell: Shell, shell: Shell,
@ -82,10 +84,13 @@ impl Compositor {
} }
} }
// XXX: try getting non-gl adapter first
// Otherwise it will panic when it drops the available adapters!
let non_gl_backends = settings.backends.difference(Backends::GL);
// only load the instance after setting environment variables, this initializes the vulkan loader // only load the instance after setting environment variables, this initializes the vulkan loader
let instance = wgpu::util::new_instance_with_webgpu_detection( let mut instance = wgpu::util::new_instance_with_webgpu_detection(
&wgpu::InstanceDescriptor { &wgpu::InstanceDescriptor {
backends: settings.backends, backends: non_gl_backends,
flags: if cfg!(feature = "strict-assertions") { flags: if cfg!(feature = "strict-assertions") {
wgpu::InstanceFlags::debugging() wgpu::InstanceFlags::debugging()
} else { } else {
@ -113,10 +118,11 @@ impl Compositor {
// } // }
#[allow(unsafe_code)] #[allow(unsafe_code)]
let compatible_surface = compatible_window let mut compatible_surface = compatible_window
.clone()
.and_then(|window| instance.create_surface(window).ok()); .and_then(|window| instance.create_surface(window).ok());
let adapter_options = wgpu::RequestAdapterOptions { let mut adapter_options = wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::from_env() power_preference: wgpu::PowerPreference::from_env()
.unwrap_or(wgpu::PowerPreference::HighPerformance), .unwrap_or(wgpu::PowerPreference::HighPerformance),
compatible_surface: compatible_surface.as_ref(), compatible_surface: compatible_surface.as_ref(),
@ -131,50 +137,13 @@ impl Compositor {
not(target_os = "redox") not(target_os = "redox")
))] ))]
if let Some((vendor_id, device_id)) = ids { if let Some((vendor_id, device_id)) = ids {
let a = instance adapter = instance
.request_adapter(&adapter_options)
.await
.map_err(|_error| {
Error::NoAdapterFound(format!("{adapter_options:?}"))
})?;
let info = a.get_info();
adapter = if info.device == device_id as u32
&& info.vendor == vendor_id as u32
{
Some(a)
} else {
instance
.enumerate_adapters(settings.backends)
.into_iter()
.filter(|adapter| {
let info = adapter.get_info();
info.device == device_id as u32
&& info.vendor == vendor_id as u32
})
.find(|adapter| {
if let Some(surface) = compatible_surface.as_ref() {
adapter.is_surface_supported(surface)
} else {
true
}
})
};
}
} else if let Ok(name) = std::env::var("WGPU_ADAPTER_NAME") {
let a = instance.request_adapter(&adapter_options).await.map_err(
|_error| Error::NoAdapterFound(format!("{adapter_options:?}")),
)?;
let info = a.get_info();
adapter = if info.name == name
{
Some(a)
} else {
instance
.enumerate_adapters(settings.backends) .enumerate_adapters(settings.backends)
.into_iter() .into_iter()
.filter(|adapter| { .filter(|adapter| {
let info = adapter.get_info(); let info = adapter.get_info();
info.name == name info.device == device_id as u32
&& info.vendor == vendor_id as u32
}) })
.find(|adapter| { .find(|adapter| {
if let Some(surface) = compatible_surface.as_ref() { if let Some(surface) = compatible_surface.as_ref() {
@ -182,30 +151,69 @@ impl Compositor {
} else { } else {
true true
} }
}) });
}; }
} else if let Ok(name) = std::env::var("WGPU_ADAPTER_NAME") {
adapter = instance
.enumerate_adapters(settings.backends)
.into_iter()
.filter(|adapter| {
let info = adapter.get_info();
info.name == name
})
.find(|adapter| {
if let Some(surface) = compatible_surface.as_ref() {
adapter.is_surface_supported(surface)
} else {
true
}
});
} }
dbg!(&adapter);
let adapter = match adapter { let adapter = match adapter {
Some(adapter) => adapter, Some(adapter) => adapter,
None => instance.request_adapter(&adapter_options).await.map_err( None => {
|_| Error::NoAdapterFound(format!("{:?}", adapter_options)), // fall back to allowing GL backend if enabled
)?, instance = wgpu::util::new_instance_with_webgpu_detection(
&wgpu::InstanceDescriptor {
backends: settings.backends,
flags: if cfg!(feature = "strict-assertions") {
wgpu::InstanceFlags::debugging()
} else {
wgpu::InstanceFlags::empty()
},
..Default::default()
},
)
.await;
compatible_surface = compatible_window
.and_then(|window| instance.create_surface(window).ok());
adapter_options = wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::from_env()
.unwrap_or(wgpu::PowerPreference::HighPerformance),
compatible_surface: compatible_surface.as_ref(),
force_fallback_adapter: false,
};
instance.request_adapter(&adapter_options).await.map_err(
|_| Error::NoAdapterFound(format!("{:?}", adapter_options)),
)?
}
}; };
log::info!("Selected: {:#?}", adapter.get_info()); log::info!("Selected: {:#?}", adapter.get_info());
let (format, alpha_mode) = compatible_surface let (format, alpha_mode) = compatible_surface
.as_ref() .as_ref()
.and_then(|surface| { .and_then(|surface: &wgpu::Surface<'_>| {
let capabilities = surface.get_capabilities(&adapter); let capabilities = surface.get_capabilities(&adapter);
let formats = capabilities.formats.iter().copied(); let formats = capabilities.formats.iter().copied();
log::info!("Available formats: {formats:#?}"); log::info!("Available formats: {formats:#?}");
let mut formats = formats.filter(|format| { let mut formats =
format.required_features() == wgpu::Features::empty() formats.filter(|format: &wgpu::TextureFormat| {
}); format.required_features() == wgpu::Features::empty()
});
let format = if color::GAMMA_CORRECTION { let format = if color::GAMMA_CORRECTION {
formats.find(wgpu::TextureFormat::is_srgb) formats.find(wgpu::TextureFormat::is_srgb)
@ -305,7 +313,7 @@ impl Compositor {
} }
/// Creates a [`Compositor`] with the given [`Settings`] and window. /// Creates a [`Compositor`] with the given [`Settings`] and window.
pub async fn new<W: compositor::Window>( pub async fn new<W: compositor::Window + Clone>(
settings: Settings, settings: Settings,
compatible_window: W, compatible_window: W,
shell: Shell, shell: Shell,
@ -363,7 +371,7 @@ impl graphics::Compositor for Compositor {
async fn with_backend( async fn with_backend(
settings: graphics::Settings, settings: graphics::Settings,
_display: impl compositor::Display, _display: impl compositor::Display,
compatible_window: impl compositor::Window, compatible_window: impl compositor::Window + Clone,
shell: Shell, shell: Shell,
backend: Option<&str>, backend: Option<&str>,
) -> Result<Self, graphics::Error> { ) -> Result<Self, graphics::Error> {