Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 78 additions & 31 deletions wgpu/src/window/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,21 @@ impl Compositor {
not(target_os = "redox")
))]
if let Some((vendor_id, device_id)) = ids {
// Trust the compositor's DMA-BUF device preference
// without probing the surface. On Wayland the surface
// may not be fully committed at this point, causing
// VK_ERROR_SURFACE_LOST_KHR in the capability query
// which falsely rejects the correct GPU. The DMA-BUF
// feedback already guarantees this device can render for
// the compositor, and the surface will be (re-)created
// on the chosen adapter later anyway.
adapter = instance
.enumerate_adapters(settings.backends)
.into_iter()
.filter(|adapter| {
.find(|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") {
Expand All @@ -189,30 +190,76 @@ impl Compositor {
let adapter = match adapter {
Some(adapter) => adapter,
None => {
// 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()
let surface_pick =
instance.request_adapter(&adapter_options).await;
let is_cpu = surface_pick
.as_ref()
.is_ok_and(|a| a.get_info().device_type == wgpu::DeviceType::Cpu);

if surface_pick.is_err() || is_cpu {
// Either no adapter was found, or only a CPU software
// rasterizer (e.g. llvmpipe) survived the surface
// compatibility filter.
//
// On Wayland the surface may not be fully committed
// yet (common for layer-shell panel applets), causing
// real GPUs to fail VK_ERROR_SURFACE_LOST_KHR while
// software rasterizers pass. Retry without the
// surface constraint so a real GPU is preferred.
//
// If the surface-less retry also yields nothing, fall
// back to the GL backend (upstream fallback) or to
// whatever the original attempt returned (possibly
// the CPU adapter) so we are never worse off.
log::warn!(
"adapter selection: surface-compatible pick is \
{pick}; retrying without surface constraint",
pick = match surface_pick.as_ref() {
Ok(a) => a.get_info().name,
Err(e) => format!("Err({e})"),
},
..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)),
)?
);
let fallback_options = wgpu::RequestAdapterOptions {
compatible_surface: None,
..adapter_options
};
match instance
.request_adapter(&fallback_options)
.await
.or(surface_pick)
{
Ok(a) => a,
Err(_) => {
// Last resort: fall back to allowing GL backend
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)),
)?
}
}
} else {
// A real (non-CPU) GPU was found -- use it.
surface_pick.expect("guaranteed Ok: is_err() was false")
}
}
};
log::info!("Selected: {:#?}", adapter.get_info());
Expand Down
19 changes: 16 additions & 3 deletions widget/src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ where

fn size(&self) -> Size<Length> {
Size {
width: Length::Shrink,
width: Length::Fill,
height: Length::Shrink,
}
}
Expand Down Expand Up @@ -344,7 +344,7 @@ where
);

let size =
limits.resolve(Length::Shrink, Length::Shrink, intrinsic_size);
limits.resolve(Length::Fill, Length::Shrink, intrinsic_size);

layout::Node::new(size)
}
Expand All @@ -363,10 +363,23 @@ where
let state = tree.state.downcast_mut::<State>();
let offset = layout.position() - Point::ORIGIN;

// Repopulate visible elements after a view() rebuild so that
// input events (which arrive before RedrawRequested in winit's
// event loop) are not silently lost.
if self.visible_elements.is_empty() {
self.visible_elements = state
.visible_layouts
.iter()
.map(|(i, _, _)| {
(self.view_item)(*i, &self.content.items[*i])
})
.collect();
}

self.visible_elements
.iter_mut()
.zip(&mut state.visible_layouts)
.map(|(element, (index, layout, tree))| {
.for_each(|(element, (index, layout, tree))| {
element.as_widget_mut().update(
tree,
event,
Expand Down