mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-11-02 18:07:04 +00:00
Windows: compile DX12 shaders with FXC (#173)
wgpu's default DX12 compiler (Auto) loads whichever dxcompiler.dll the DLL search path finds. The launcher ships none, and without a matching dxil.dll the unsigned-DXIL warning fails wgpu's indirect-validation pipeline, the device is lost and the launcher exits before the first frame. Pin the compiler to FXC, which is part of Windows; WGPU_DX12_COMPILER still overrides it. GL stays in the Windows backends: it is the deliberate fallback for machines whose D3D12 adapters can't present to the window. Fixes #126 Co-authored-by: Fabio Lussi <198260595+itrycodinganditsbad@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -148,11 +148,12 @@ fn native_options(hidden: bool) -> eframe::NativeOptions {
|
||||
/// 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, and then
|
||||
/// wgpu picks the adapter itself.
|
||||
/// wgpu picks the adapter itself. Direct3D 12 shaders compile with FXC ([`pin_dx12_compiler`]).
|
||||
#[cfg(windows)]
|
||||
fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
use eframe::wgpu::{Backends, PowerPreference};
|
||||
use eframe::wgpu::{Backends, Dx12Compiler, PowerPreference};
|
||||
let mut config = eframe::WgpuConfiguration::default();
|
||||
pin_dx12_compiler(&mut config, Dx12Compiler::from_env());
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
if let Some(backends) = Backends::from_env() {
|
||||
setup.instance_descriptor.backends = backends;
|
||||
@@ -175,6 +176,19 @@ fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
config
|
||||
}
|
||||
|
||||
/// Compiles Direct3D 12 shaders with FXC (`d3dcompiler_47.dll`, part of Windows) unless
|
||||
/// `env_choice` (normally `Dx12Compiler::from_env()`, i.e. `WGPU_DX12_COMPILER`) names another.
|
||||
/// wgpu's default (`Auto`) loads whichever `dxcompiler.dll` the DLL search path finds. The launcher
|
||||
/// ships none, and without a matching `dxil.dll` DXC warns that the DXIL is unsigned; wgpu takes
|
||||
/// the warning for a compile error, its indirect-validation pipeline fails, the device is lost
|
||||
/// and the launcher exits before the first frame (#126).
|
||||
#[cfg(any(windows, test))]
|
||||
fn pin_dx12_compiler(config: &mut eframe::WgpuConfiguration, env_choice: Option<eframe::wgpu::Dx12Compiler>) {
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
setup.instance_descriptor.backend_options.dx12.shader_compiler = env_choice.unwrap_or(eframe::wgpu::Dx12Compiler::Fxc);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@@ -896,6 +910,27 @@ mod tests {
|
||||
assert!(!shell.launcher.closed_to_tray);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dx12_shaders_compile_with_fxc_unless_asked() {
|
||||
use eframe::egui_wgpu::WgpuSetup;
|
||||
use eframe::wgpu::Dx12Compiler;
|
||||
fn compiler(env_choice: Option<Dx12Compiler>) -> Dx12Compiler {
|
||||
let mut config = eframe::WgpuConfiguration::default();
|
||||
if let WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
// wgpu's default: whichever dxcompiler.dll the DLL search path finds (#126).
|
||||
setup.instance_descriptor.backend_options.dx12.shader_compiler = Dx12Compiler::Auto;
|
||||
}
|
||||
pin_dx12_compiler(&mut config, env_choice);
|
||||
match config.wgpu_setup {
|
||||
WgpuSetup::CreateNew(setup) => setup.instance_descriptor.backend_options.dx12.shader_compiler,
|
||||
WgpuSetup::Existing(_) => panic!("the default configuration creates its own instance"),
|
||||
}
|
||||
}
|
||||
assert!(matches!(compiler(None), Dx12Compiler::Fxc));
|
||||
assert!(matches!(compiler(Some(Dx12Compiler::Auto)), Dx12Compiler::Auto));
|
||||
assert!(matches!(compiler(Some(Dx12Compiler::default_dynamic_dxc())), Dx12Compiler::DynamicDxc { .. }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warp_beats_a_gl_gpu_but_not_a_d3d12_gpu() {
|
||||
use eframe::wgpu::{Backend, DeviceType};
|
||||
|
||||
Reference in New Issue
Block a user