mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-10-14 14:26:48 -04:00
Windows: prefer Direct3D 12 (including WARP) over GL when picking a GPU (#105)
* fix(wgpu): prefer D3D12 (incl. WARP) over GL on Windows (#2087) On Windows, rank any Direct3D 12 adapter (WARP included) above GL when WGPU_BACKEND is unset. wgpu ranks WARP last, so GPUs without a D3D12 driver (Intel HD 4000, Radeon TeraScale) got the GL adapter, whose legacy driver fails Surface::configure; wgpu panics on that before any app code runs. Hardware D3D12 adapters keep wgpu's order. Reporter verified WGPU_BACKEND=d3d12 (WARP) works on the affected machine. Refs storytold/artcraft#2087 * Drop a reference to an issue number from another tracker Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Brandon Thomas <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 file changed
+51
-3
@@ -119,17 +119,51 @@ fn native_options(hidden: bool) -> eframe::NativeOptions {
|
||||
/// Vulkan goes through vendor ICDs and third-party overlay layers, and on hybrid AMD laptops whose
|
||||
/// integrated and discrete GPUs run different driver packages (common on OEM machines, where the
|
||||
/// Adrenalin installer leaves the integrated GPU on the OEM driver) it crashes inside
|
||||
/// `amdvlk64.dll` before the first frame. `WGPU_BACKEND` still overrides the default.
|
||||
/// `amdvlk64.dll` before the first frame. `WGPU_BACKEND` still overrides the default, and then
|
||||
/// wgpu picks the adapter itself.
|
||||
#[cfg(windows)]
|
||||
fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
use eframe::wgpu::Backends;
|
||||
use eframe::wgpu::{Backends, PowerPreference};
|
||||
let mut config = eframe::WgpuConfiguration::default();
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
setup.instance_descriptor.backends = Backends::from_env().unwrap_or(Backends::DX12 | Backends::GL);
|
||||
if let Some(backends) = Backends::from_env() {
|
||||
setup.instance_descriptor.backends = backends;
|
||||
} else {
|
||||
setup.instance_descriptor.backends = Backends::DX12 | Backends::GL;
|
||||
let integrated = setup.power_preference == PowerPreference::LowPower;
|
||||
setup.native_adapter_selector = Some(Arc::new(move |adapters, surface| {
|
||||
adapters
|
||||
.iter()
|
||||
.filter(|a| surface.is_none_or(|s| a.is_surface_supported(s)))
|
||||
.min_by_key(|a| {
|
||||
let info = a.get_info();
|
||||
adapter_rank(info.backend, info.device_type, integrated)
|
||||
})
|
||||
.cloned()
|
||||
.ok_or_else(|| "no graphics adapter can draw to the window".to_owned())
|
||||
}));
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
/// wgpu's own adapter order (by device type, then enumeration order), except that any Direct3D 12
|
||||
/// adapter, the WARP software one included, comes before GL. wgpu ranks WARP last, so on GPUs with
|
||||
/// no D3D12 driver (Intel HD 4000, Radeon TeraScale) it picked the GL one, whose legacy driver
|
||||
/// failed `Surface::configure` and wgpu panicked before the window opened.
|
||||
#[cfg(any(windows, test))]
|
||||
fn adapter_rank(backend: eframe::wgpu::Backend, device_type: eframe::wgpu::DeviceType, integrated: bool) -> (bool, u8) {
|
||||
use eframe::wgpu::{Backend, DeviceType};
|
||||
let device = match device_type {
|
||||
DeviceType::DiscreteGpu => 1 + u8::from(integrated),
|
||||
DeviceType::IntegratedGpu => 2 - u8::from(integrated),
|
||||
DeviceType::Other => 3,
|
||||
DeviceType::VirtualGpu => 4,
|
||||
DeviceType::Cpu => 5,
|
||||
};
|
||||
(backend != Backend::Dx12, device)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
eframe::WgpuConfiguration::default()
|
||||
@@ -754,4 +788,18 @@ mod tests {
|
||||
assert!(!shell.visible);
|
||||
assert!(!shell.launcher.closed_to_tray);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warp_beats_a_gl_gpu_but_not_a_d3d12_gpu() {
|
||||
use eframe::wgpu::{Backend, DeviceType};
|
||||
// Intel HD 4000 + Radeon HD 7600M have no D3D12 driver; their GL one fails to configure.
|
||||
let warp = adapter_rank(Backend::Dx12, DeviceType::Cpu, false);
|
||||
assert!(warp < adapter_rank(Backend::Gl, DeviceType::IntegratedGpu, false));
|
||||
assert!(warp < adapter_rank(Backend::Gl, DeviceType::Other, false));
|
||||
// Hardware D3D12 still wins, in wgpu's order for the power preference.
|
||||
let (discrete, integrated) = (DeviceType::DiscreteGpu, DeviceType::IntegratedGpu);
|
||||
assert!(adapter_rank(Backend::Dx12, integrated, false) < warp);
|
||||
assert!(adapter_rank(Backend::Dx12, discrete, false) < adapter_rank(Backend::Dx12, integrated, false));
|
||||
assert!(adapter_rank(Backend::Dx12, integrated, true) < adapter_rank(Backend::Dx12, discrete, true));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user