From 8cd37e0a6814739098be2aed2e42f0b7a4fdb4a7 Mon Sep 17 00:00:00 2001 From: Christian Svensson Date: Sat, 17 Oct 2026 16:31:33 +0200 Subject: [PATCH] gpu: take wgpu's backend options from its environment variables The adapter selection built its wgpu instance with default backend options, so WGPU_DX12_COMPILER had no effect: on DX12 there was no way to choose between FXC and DXC when measuring them (#561: FXC takes ~8.5 s to create the GPU solver's pipelines and runs it at half of Vulkan's speed, DXC 0.5 s and full speed). The options now come from wgpu's own environment variables. staticdxc is refused with an error: it needs wgpu's static-dxc feature, which FieldCraft does not build, and wgpu would panic on it. Part of #561. --- crates/gpu/src/select.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/gpu/src/select.rs b/crates/gpu/src/select.rs index 2975bf3..5213eea 100644 --- a/crates/gpu/src/select.rs +++ b/crates/gpu/src/select.rs @@ -8,6 +8,11 @@ //! Backends are Metal on macOS, DX12 and Vulkan on Windows, Vulkan and GL elsewhere; //! `WGPU_BACKEND` narrows them. A discrete GPU outranks an integrated one, then a virtual one, //! then any other; a CPU device is the software tier. +//! +//! wgpu's backend options follow its environment variables: on DX12, `WGPU_DX12_COMPILER` +//! (`fxc` or `dxc`; unset, DXC when `dxcompiler.dll` is on the DLL search path, else FXC, see +//! #561). `staticdxc` is refused: it needs wgpu's `static-dxc` feature, which FieldCraft does not +//! build, and wgpu would panic on it. use crate::{GpuError, Result}; @@ -100,7 +105,11 @@ pub fn adapter(policy: Policy) -> Result> { if policy == Policy::Cpu { return Ok(None); } - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: backends(), ..wgpu::InstanceDescriptor::new_without_display_handle() }); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: backends(), + backend_options: backend_options(wgpu::BackendOptions::from_env_or_default())?, + ..wgpu::InstanceDescriptor::new_without_display_handle() + }); let mut adapters = pollster::block_on(instance.enumerate_adapters(backends())); let types: Vec<_> = adapters.iter().map(|a| a.get_info().device_type).collect(); let Some(i) = pick(&types, policy)? else { return Ok(None) }; @@ -108,12 +117,32 @@ pub fn adapter(policy: Policy) -> Result> { Ok((i < adapters.len()).then(|| (adapters.swap_remove(i), tier))) } +/// `options`, unless they ask for a DX12 compiler this build does not have. +fn backend_options(options: wgpu::BackendOptions) -> Result { + if matches!(options.dx12.shader_compiler, wgpu::Dx12Compiler::StaticDxc) { + return Err(GpuError::Device("WGPU_DX12_COMPILER=staticdxc is not built in: use dxc with dxcompiler.dll, or fxc".into())); + } + Ok(options) +} + #[cfg(test)] mod tests { use wgpu::DeviceType::*; use super::*; + #[test] + fn a_dx12_compiler_that_is_not_built_in_is_refused() { + let with = |shader_compiler| { + let mut o = wgpu::BackendOptions::default(); + o.dx12.shader_compiler = shader_compiler; + backend_options(o) + }; + assert!(with(wgpu::Dx12Compiler::Fxc).is_ok()); + assert!(with(wgpu::Dx12Compiler::Auto).is_ok()); + assert!(with(wgpu::Dx12Compiler::StaticDxc).is_err()); + } + #[test] fn policies_walk_the_tiers() { assert_eq!(pick(&[Cpu, IntegratedGpu, DiscreteGpu, VirtualGpu], Policy::Auto), Ok(Some(2)));