diff --git a/CHANGELOG.md b/CHANGELOG.md index bd054fcc5f..231470f275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,10 +103,54 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non `Instance::create_surface()` now returns `Result` instead of `Surface`. This allows an error to be returned instead of panicking if the given window is a HTML canvas and obtaining a WebGPU or WebGL 2 context fails. (No other platforms currently report any errors through this path.) By @kpreid in [#3052](https://github.com/gfx-rs/wgpu/pull/3052/) +#### Instance creation now takes `InstanceDescriptor` instead of `Backends` + +`Instance::new()` and `hub::Global::new()` now take an `InstanceDescriptor` struct which cointains both the existing `Backends` selection as well as a new `Dx12Compiler` field for selecting which Dx12 shader compiler to use. + +```diff +- let instance = Instance::new(wgpu::Backends::all()); ++ let instance = Instance::new(wgpu::InstanceDescriptor { ++ backends: wgpu::Backends::all(), ++ dx12_shader_compiler: wgpu::Dx12Compiler::Fxc, ++ }); +``` + +```diff +- let global = wgc::hub::Global::new( +- "player", +- IdentityPassThroughFactory, +- wgpu::Backends::all(), +- ); ++ let global = wgc::hub::Global::new( ++ "player", ++ IdentityPassThroughFactory, ++ wgpu::InstanceDescriptor { ++ backends: wgpu::Backends::all(), ++ dx12_shader_compiler: wgpu::Dx12Compiler::Fxc, ++ }, ++ ); +``` + +`Instance` now also also implements `Default`, which uses `wgpu::Backends::all()` and `wgpu::Dx12Compiler::Fxc` for `InstanceDescriptor` + +```diff +- let instance = Instance::new(wgpu::InstanceDescriptor { +- backends: wgpu::Backends::all(), +- dx12_shader_compiler: wgpu::Dx12Compiler::Fxc, +- }); ++ let instance = Instance::default(); +``` + +By @Elabajaba in [#3356](https://github.com/gfx-rs/wgpu/pull/3356) + #### Suballocate DX12 buffers and textures `wgpu`'s DX12 backend can now suballocate buffers and textures when the `windows_rs` feature is enabled, which can give a significant increase in performance (in testing I've seen a 10000%+ improvement in a simple scene with 200 `write_buffer` calls per frame, and a 40%+ improvement in [Bistro using Bevy](https://github.com/vleue/bevy_bistro_playground)). Previously `wgpu-hal`'s DX12 backend created a new heap on the GPU every time you called write_buffer (by calling `CreateCommittedResource`), whereas now with the `windows_rs` feature enabled it uses [`gpu_allocator`](https://crates.io/crates/gpu-allocator) to manage GPU memory (and calls `CreatePlacedResource` with a suballocated heap). By @Elabajaba in [#3163](https://github.com/gfx-rs/wgpu/pull/3163) +#### DXC Shader Compiler Support for DX12 + +You can now choose to use the DXC compiler for DX12 instead of FXC. The DXC compiler is faster, less buggy, and allows for new features compared to the old, unmaintained FXC compiler. You can choose which compiler to use at `Instance` creation using the `Dx12Compiler` field in the `InstanceDescriptor` struct. Note that DXC requires both `dxcompiler.dll` and `dxil.dll`, which can be downloaded from https://github.com/microsoft/DirectXShaderCompiler/releases. Both .dlls need to be shipped with your application when targeting DX12 and using the `DXC` compiler. If the .dlls can't be loaded, then it will fall back to the FXC compiler. By @39ali and @Elabajaba in [#3356](https://github.com/gfx-rs/wgpu/pull/3356) + #### Texture Format Reinterpretation The `view_formats` field is used to specify formats that are compatible with the texture format to allow the creation of views with different formats, currently, only changing srgb-ness is allowed. diff --git a/Cargo.lock b/Cargo.lock index 6a93c95b1a..ead516d556 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,6 +340,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "com-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" + [[package]] name = "concurrent-queue" version = "2.0.0" @@ -1178,6 +1184,21 @@ dependencies = [ "ahash", ] +[[package]] +name = "hassle-rs" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90601c6189668c7345fc53842cb3f3a3d872203d523be1b3cb44a36a3e62fb85" +dependencies = [ + "bitflags", + "com-rs", + "libc", + "libloading", + "thiserror", + "widestring", + "winapi", +] + [[package]] name = "heck" version = "0.3.3" @@ -2971,6 +2992,7 @@ dependencies = [ "gpu-alloc", "gpu-allocator", "gpu-descriptor", + "hassle-rs", "js-sys", "khronos-egl", "libc", @@ -3021,6 +3043,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index d0ffea48da..ef5ad81d64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ gpu-allocator = { version = "0.21", default_features = false, features = ["d3d12 native = { package = "d3d12", version = "0.5.0" } range-alloc = "0.1" winapi = "0.3" +hassle-rs = "0.9.0" # Gles dependencies egl = { package = "khronos-egl", version = "4.1" } diff --git a/README.md b/README.md index 6cc44d0184..fb725d0604 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ All testing and example infrastructure shares the same set of environment variab - `WGPU_ADAPTER_NAME` with a substring of the name of the adapter you want to use (ex. `1080` will match `NVIDIA GeForce 1080ti`). - `WGPU_BACKEND` with a comma separated list of the backends you want to use (`vulkan`, `metal`, `dx12`, `dx11`, or `gl`). - `WGPU_POWER_PREF` with the power preference to choose when a specific adapter name isn't specified (`high` or `low`) +- `WGPU_DX12_COMPILER` with the DX12 shader compiler you wish to use (`dxc` or `fxc`, note that `dxc` requires `dxil.dll` and `dxcompiler.dll` to be in the working directory otherwise it will fall back to `fxc`) When running the CTS, use the variables `DENO_WEBGPU_ADAPTER_NAME`, `DENO_WEBGPU_BACKEND`, `DENO_WEBGPU_POWER_PREFERENCE`. diff --git a/deno_webgpu/src/lib.rs b/deno_webgpu/src/lib.rs index 75b4bb6d28..23c49ac679 100644 --- a/deno_webgpu/src/lib.rs +++ b/deno_webgpu/src/lib.rs @@ -252,7 +252,10 @@ pub async fn op_webgpu_request_adapter( state.put(wgpu_core::hub::Global::new( "webgpu", wgpu_core::hub::IdentityManagerFactory, - backends, + wgpu_types::InstanceDescriptor { + backends, + dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc, + }, )); state.borrow::() }; diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 3ccc11c270..fb2665e3a3 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -43,7 +43,11 @@ fn main() { .build(&event_loop) .unwrap(); - let global = wgc::hub::Global::new("player", IdentityPassThroughFactory, wgt::Backends::all()); + let global = wgc::hub::Global::new( + "player", + IdentityPassThroughFactory, + wgt::InstanceDescriptor::default(), + ); let mut command_buffer_id_manager = wgc::hub::IdentityManager::default(); #[cfg(feature = "winit")] diff --git a/player/tests/test.rs b/player/tests/test.rs index 06da011a49..750b823648 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -178,7 +178,14 @@ impl Corpus { let dir = path.parent().unwrap(); let corpus: Corpus = ron::de::from_reader(File::open(&path).unwrap()).unwrap(); - let global = wgc::hub::Global::new("test", IdentityPassThroughFactory, corpus.backends); + let global = wgc::hub::Global::new( + "test", + IdentityPassThroughFactory, + wgt::InstanceDescriptor { + backends: corpus.backends, + dx12_shader_compiler: wgt::Dx12Compiler::Fxc, + }, + ); for &backend in BACKENDS { if !corpus.backends.contains(backend.into()) { continue; diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 290df3c716..17748b5773 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -1108,10 +1108,10 @@ pub struct Global { } impl Global { - pub fn new(name: &str, factory: G, backends: wgt::Backends) -> Self { + pub fn new(name: &str, factory: G, instance_desc: wgt::InstanceDescriptor) -> Self { profiling::scope!("Global::new"); Self { - instance: Instance::new(name, backends), + instance: Instance::new(name, instance_desc), surfaces: Registry::without_backend(&factory, "Surface"), hubs: Hubs::new(&factory), } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 5bbf03543f..d8ecd49056 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -67,9 +67,9 @@ pub struct Instance { } impl Instance { - pub fn new(name: &str, backends: Backends) -> Self { - fn init(_: A, mask: Backends) -> Option { - if mask.contains(A::VARIANT.into()) { + pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self { + fn init(_: A, instance_desc: &wgt::InstanceDescriptor) -> Option { + if instance_desc.backends.contains(A::VARIANT.into()) { let mut flags = hal::InstanceFlags::empty(); if cfg!(debug_assertions) { flags |= hal::InstanceFlags::VALIDATION; @@ -78,6 +78,7 @@ impl Instance { let hal_desc = hal::InstanceDescriptor { name: "wgpu", flags, + dx12_shader_compiler: instance_desc.dx12_shader_compiler.clone(), }; unsafe { hal::Instance::init(&hal_desc).ok() } } else { @@ -88,15 +89,15 @@ impl Instance { Self { name: name.to_string(), #[cfg(feature = "vulkan")] - vulkan: init(hal::api::Vulkan, backends), + vulkan: init(hal::api::Vulkan, &instance_desc), #[cfg(feature = "metal")] - metal: init(hal::api::Metal, backends), + metal: init(hal::api::Metal, &instance_desc), #[cfg(feature = "dx12")] - dx12: init(hal::api::Dx12, backends), + dx12: init(hal::api::Dx12, &instance_desc), #[cfg(feature = "dx11")] - dx11: init(hal::api::Dx11, backends), + dx11: init(hal::api::Dx11, &instance_desc), #[cfg(feature = "gles")] - gl: init(hal::api::Gles, backends), + gl: init(hal::api::Gles, &instance_desc), } } diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 16389287e6..33a9f3b059 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -35,6 +35,7 @@ dx11 = ["naga/hlsl-out", "native", "libloading", "winapi/d3d11", "winapi/d3d11_1 dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"] # TODO: This is a separate feature until Mozilla okays windows-rs, see https://github.com/gfx-rs/wgpu/issues/3207 for the tracking issue. windows_rs = ["gpu-allocator"] +dxc_shader_compiler = ["hassle-rs"] renderdoc = ["libloading", "renderdoc-sys"] emscripten = ["gles"] @@ -75,6 +76,7 @@ glow = { git = "https://github.com/grovesNL/glow", rev = "c8a011fcd57a5c68cc917e bit-set = { version = "0.5", optional = true } range-alloc = { version = "0.1", optional = true } gpu-allocator = { version = "0.21", default_features = false, features = ["d3d12", "windows", "public-winapi"], optional = true } +hassle-rs = { version = "0.9", optional = true } [dependencies.wgt] package = "wgpu-types" diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 7b3ea12c0a..849be37c60 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -96,6 +96,8 @@ impl Example { } else { hal::InstanceFlags::empty() }, + // Can't rely on having DXC available, so use FXC instead + dx12_shader_compiler: wgt::Dx12Compiler::Fxc, }; let instance = unsafe { A::Instance::init(&instance_desc)? }; let mut surface = unsafe { diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 2119ebd522..a3136b55d6 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -52,6 +52,7 @@ impl super::Adapter { adapter: native::DxgiAdapter, library: &Arc, instance_flags: crate::InstanceFlags, + dx12_shader_compiler: &wgt::Dx12Compiler, ) -> Option> { // Create the device so that we can get the capabilities. let device = { @@ -243,6 +244,7 @@ impl super::Adapter { private_caps, presentation_timer, workarounds, + dx12_shader_compiler: dx12_shader_compiler.clone(), }, info, features, @@ -347,7 +349,13 @@ impl crate::Adapter for super::Adapter { .into_device_result("Queue creation")? }; - let device = super::Device::new(self.device, queue, self.private_caps, &self.library)?; + let device = super::Device::new( + self.device, + queue, + self.private_caps, + &self.library, + self.dx12_shader_compiler.clone(), + )?; Ok(crate::OpenDevice { device, queue: super::Queue { diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index b9a0c7e566..fb2c3f92fc 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -5,10 +5,10 @@ use crate::{ use super::{conv, descriptor, view}; use parking_lot::Mutex; -use std::{ffi, mem, num::NonZeroU32, ptr, slice, sync::Arc}; +use std::{ffi, mem, num::NonZeroU32, ptr, sync::Arc}; use winapi::{ shared::{dxgiformat, dxgitype, minwindef::BOOL, winerror}, - um::{d3d12, d3dcompiler, synchapi, winbase}, + um::{d3d12, synchapi, winbase}, Interface, }; @@ -21,9 +21,18 @@ impl super::Device { present_queue: native::CommandQueue, private_caps: super::PrivateCapabilities, library: &Arc, + dx12_shader_compiler: wgt::Dx12Compiler, ) -> Result { let mem_allocator = super::suballocation::create_allocator_wrapper(&raw)?; + let dxc_container = match dx12_shader_compiler { + wgt::Dx12Compiler::Dxc { + dxil_path, + dxc_path, + } => super::shader_compilation::get_dxc_container(dxc_path, dxil_path)?, + wgt::Dx12Compiler::Fxc => None, + }; + let mut idle_fence = native::Fence::null(); let hr = unsafe { profiling::scope!("ID3D12Device::CreateFence"); @@ -166,6 +175,7 @@ impl super::Device { render_doc: Default::default(), null_rtv_handle, mem_allocator, + dxc_container, }) } @@ -192,7 +202,7 @@ impl super::Device { stage: &crate::ProgrammableStage, layout: &super::PipelineLayout, naga_stage: naga::ShaderStage, - ) -> Result { + ) -> Result { use naga::back::hlsl; let stage_bit = crate::auxil::map_naga_stage(naga_stage); @@ -212,72 +222,44 @@ impl super::Device { naga_stage.to_hlsl_str(), layout.naga_options.shader_model.to_str() ); + let ep_index = module .entry_points .iter() .position(|ep| ep.stage == naga_stage && ep.name == stage.entry_point) .ok_or(crate::PipelineError::EntryPoint(naga_stage))?; + let raw_ep = reflection_info.entry_point_names[ep_index] .as_ref() - .map(|name| ffi::CString::new(name.as_str()).unwrap()) .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("{}", e)))?; - let mut shader_data = native::Blob::null(); - let mut error = native::Blob::null(); - let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS; - if self - .private_caps - .instance_flags - .contains(crate::InstanceFlags::DEBUG) - { - compile_flags |= - d3dcompiler::D3DCOMPILE_DEBUG | d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; - } - - let source_name = match stage.module.raw_name { - Some(ref cstr) => cstr.as_c_str().as_ptr(), - None => ptr::null(), - }; + let source_name = stage + .module + .raw_name + .as_ref() + .and_then(|cstr| cstr.to_str().ok()) + .unwrap_or_default(); - let hr = unsafe { - profiling::scope!("d3dcompiler::D3DCompile"); - d3dcompiler::D3DCompile( - source.as_ptr() as *const _, - source.len(), + // Compile with DXC if available, otherwise fall back to FXC + let (result, log_level) = if let Some(ref dxc_container) = self.dxc_container { + super::shader_compilation::compile_dxc( + self, + &source, source_name, - ptr::null(), - ptr::null_mut(), - raw_ep.as_ptr(), - full_stage.as_ptr() as *const i8, - compile_flags, - 0, - shader_data.mut_void() as *mut *mut _, - error.mut_void() as *mut *mut _, + raw_ep, + stage_bit, + full_stage, + dxc_container, + ) + } else { + super::shader_compilation::compile_fxc( + self, + &source, + source_name, + &ffi::CString::new(raw_ep.as_str()).unwrap(), + stage_bit, + full_stage, ) - }; - - let (result, log_level) = match hr.into_result() { - Ok(()) => (Ok(shader_data), log::Level::Info), - Err(e) => { - let mut full_msg = format!("D3DCompile error ({})", e); - if !error.is_null() { - use std::fmt::Write as _; - let message = unsafe { - slice::from_raw_parts( - error.GetBufferPointer() as *const u8, - error.GetBufferSize(), - ) - }; - let _ = write!(full_msg, ": {}", String::from_utf8_lossy(message)); - unsafe { - error.destroy(); - } - } - ( - Err(crate::PipelineError::Linkage(stage_bit, full_msg)), - log::Level::Warn, - ) - } }; log::log!( @@ -1078,7 +1060,12 @@ impl crate::Device for super::Device { }, bind_group_infos, naga_options: hlsl::Options { - shader_model: hlsl::ShaderModel::V5_1, + shader_model: match self.dxc_container { + // DXC + Some(_) => hlsl::ShaderModel::V6_0, + // FXC doesn't support SM 6.0 + None => hlsl::ShaderModel::V5_1, + }, binding_map, fake_missing_bindings: false, special_constants_binding, @@ -1294,9 +1281,9 @@ impl crate::Device for super::Device { let blob_fs = match desc.fragment_stage { Some(ref stage) => { shader_stages |= wgt::ShaderStages::FRAGMENT; - self.load_shader(stage, desc.layout, naga::ShaderStage::Fragment)? + Some(self.load_shader(stage, desc.layout, naga::ShaderStage::Fragment)?) } - None => native::Blob::null(), + None => None, }; let mut vertex_strides = [None; crate::MAX_VERTEX_BUFFERS]; @@ -1369,11 +1356,10 @@ impl crate::Device for super::Device { let raw_desc = d3d12::D3D12_GRAPHICS_PIPELINE_STATE_DESC { pRootSignature: desc.layout.shared.signature.as_mut_ptr(), - VS: *native::Shader::from_blob(blob_vs), - PS: if blob_fs.is_null() { - *native::Shader::null() - } else { - *native::Shader::from_blob(blob_fs) + VS: *blob_vs.create_native_shader(), + PS: match blob_fs { + Some(ref shader) => *shader.create_native_shader(), + None => *native::Shader::null(), }, GS: *native::Shader::null(), DS: *native::Shader::null(), @@ -1445,9 +1431,9 @@ impl crate::Device for super::Device { }; unsafe { blob_vs.destroy() }; - if !blob_fs.is_null() { + if let Some(blob_fs) = blob_fs { unsafe { blob_fs.destroy() }; - } + }; hr.into_result() .map_err(|err| crate::PipelineError::Linkage(shader_stages, err.into_owned()))?; @@ -1478,7 +1464,7 @@ impl crate::Device for super::Device { profiling::scope!("ID3D12Device::CreateComputePipelineState"); self.raw.create_compute_pipeline_state( desc.layout.shared.signature, - native::Shader::from_blob(blob_cs), + blob_cs.create_native_shader(), 0, native::CachedPSO::null(), native::PipelineStateFlags::empty(), diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index 71f53e140e..7829c6fe87 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -64,6 +64,7 @@ impl crate::Instance for super::Instance { _lib_dxgi: lib_dxgi, supports_allow_tearing, flags: desc.flags, + dx12_shader_compiler: desc.dx12_shader_compiler.clone(), }) } @@ -91,7 +92,9 @@ impl crate::Instance for super::Instance { adapters .into_iter() - .filter_map(|raw| super::Adapter::expose(raw, &self.library, self.flags)) + .filter_map(|raw| { + super::Adapter::expose(raw, &self.library, self.flags, &self.dx12_shader_compiler) + }) .collect() } } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 162d0eb99a..26c7b2b8d0 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -39,6 +39,7 @@ mod conv; mod descriptor; mod device; mod instance; +mod shader_compilation; mod suballocation; mod view; @@ -92,6 +93,7 @@ pub struct Instance { supports_allow_tearing: bool, _lib_dxgi: native::DxgiLib, flags: crate::InstanceFlags, + dx12_shader_compiler: wgt::Dx12Compiler, } impl Instance { @@ -173,6 +175,7 @@ pub struct Adapter { //Note: this isn't used right now, but we'll need it later. #[allow(unused)] workarounds: Workarounds, + dx12_shader_compiler: wgt::Dx12Compiler, } unsafe impl Send for Adapter {} @@ -241,6 +244,7 @@ pub struct Device { render_doc: crate::auxil::renderdoc::RenderDoc, null_rtv_handle: descriptor::Handle, mem_allocator: Option>, + dxc_container: Option, } unsafe impl Send for Device {} @@ -538,6 +542,30 @@ pub struct ShaderModule { raw_name: Option, } +pub(super) enum CompiledShader { + #[allow(unused)] + Dxc(Vec), + Fxc(native::Blob), +} + +impl CompiledShader { + fn create_native_shader(&self) -> native::Shader { + match *self { + CompiledShader::Dxc(ref shader) => native::Shader::from_raw(shader), + CompiledShader::Fxc(shader) => native::Shader::from_blob(shader), + } + } + + unsafe fn destroy(self) { + match self { + CompiledShader::Dxc(_) => {} + CompiledShader::Fxc(shader) => unsafe { + shader.destroy(); + }, + } + } +} + pub struct RenderPipeline { raw: native::PipelineState, layout: PipelineLayoutShared, diff --git a/wgpu-hal/src/dx12/shader_compilation.rs b/wgpu-hal/src/dx12/shader_compilation.rs new file mode 100644 index 0000000000..bc81d10fd0 --- /dev/null +++ b/wgpu-hal/src/dx12/shader_compilation.rs @@ -0,0 +1,255 @@ +use std::ptr; + +pub(super) use dxc::{compile_dxc, get_dxc_container, DxcContainer}; +use winapi::um::d3dcompiler; + +use crate::auxil::dxgi::result::HResult; + +// This exists so that users who don't want to use dxc can disable the dxc_shader_compiler feature +// and not have to compile hassle_rs. +// Currently this will use Dxc if it is chosen as the dx12 compiler at `Instance` creation time, and will +// fallback to FXC if the Dxc libraries (dxil.dll and dxcompiler.dll) are not found, or if Fxc is chosen at' +// `Instance` creation time. + +pub(super) fn compile_fxc( + device: &super::Device, + source: &String, + source_name: &str, + raw_ep: &std::ffi::CString, + stage_bit: wgt::ShaderStages, + full_stage: String, +) -> ( + Result, + log::Level, +) { + profiling::scope!("compile_fxc"); + let mut shader_data = native::Blob::null(); + let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS; + if device + .private_caps + .instance_flags + .contains(crate::InstanceFlags::DEBUG) + { + compile_flags |= d3dcompiler::D3DCOMPILE_DEBUG | d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; + } + let mut error = native::Blob::null(); + let hr = unsafe { + profiling::scope!("d3dcompiler::D3DCompile"); + d3dcompiler::D3DCompile( + source.as_ptr().cast(), + source.len(), + source_name.as_ptr().cast(), + ptr::null(), + ptr::null_mut(), + raw_ep.as_ptr(), + full_stage.as_ptr().cast(), + compile_flags, + 0, + shader_data.mut_void().cast(), + error.mut_void().cast(), + ) + }; + + match hr.into_result() { + Ok(()) => ( + Ok(super::CompiledShader::Fxc(shader_data)), + log::Level::Info, + ), + Err(e) => { + let mut full_msg = format!("FXC D3DCompile error ({})", e); + if !error.is_null() { + use std::fmt::Write as _; + let message = unsafe { + std::slice::from_raw_parts( + error.GetBufferPointer() as *const u8, + error.GetBufferSize(), + ) + }; + let _ = write!(full_msg, ": {}", String::from_utf8_lossy(message)); + unsafe { + error.destroy(); + } + } + ( + Err(crate::PipelineError::Linkage(stage_bit, full_msg)), + log::Level::Warn, + ) + } + } +} + +// The Dxc implementation is behind a feature flag so that users who don't want to use dxc can disable the feature. +#[cfg(feature = "dxc_shader_compiler")] +mod dxc { + use std::path::PathBuf; + + pub(crate) struct DxcContainer { + pub compiler: hassle_rs::DxcCompiler, + pub library: hassle_rs::DxcLibrary, + // Has to be held onto for the lifetime of the device otherwise shaders will fail to compile + _dxc: hassle_rs::Dxc, + } + + pub(crate) fn get_dxc_container( + dxc_path: Option, + dxil_path: Option, + ) -> Result, crate::DeviceError> { + // Make sure that dxil.dll exists. + match hassle_rs::Dxil::new(dxil_path) { + Ok(_) => (), + Err(e) => { + log::warn!("Failed to load dxil.dll. Defaulting to Fxc instead: {}", e); + return Ok(None); + } + }; + + let dxc = match hassle_rs::Dxc::new(dxc_path) { + Ok(dxc) => dxc, + Err(e) => { + log::warn!( + "Failed to load dxcompiler.dll. Defaulting to Fxc instead: {}", + e + ); + return Ok(None); + } + }; + let dxc_compiler = dxc.create_compiler()?; + let dxc_library = dxc.create_library()?; + + Ok(Some(DxcContainer { + _dxc: dxc, + compiler: dxc_compiler, + library: dxc_library, + })) + } + + pub(crate) fn compile_dxc( + device: &crate::dx12::Device, + source: &str, + source_name: &str, + raw_ep: &str, + stage_bit: wgt::ShaderStages, + full_stage: String, + dxc_container: &DxcContainer, + ) -> ( + Result, + log::Level, + ) { + profiling::scope!("compile_dxc"); + let mut compile_flags = arrayvec::ArrayVec::<&str, 3>::new_const(); + compile_flags.push("-Ges"); // d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS + if device + .private_caps + .instance_flags + .contains(crate::InstanceFlags::DEBUG) + { + compile_flags.push("-Zi"); // d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION + compile_flags.push("-Od"); // d3dcompiler::D3DCOMPILE_DEBUG + } + + let blob = match dxc_container + .library + .create_blob_with_encoding_from_str(source) + .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("DXC blob error: {}", e))) + { + Ok(blob) => blob, + Err(e) => return (Err(e), log::Level::Error), + }; + + // DXC will automatically validate the shaders during compilation as long as dxil.dll is available, so we don't need to do it ourselves. + let compiled = dxc_container.compiler.compile( + &blob, + source_name, + raw_ep, + &full_stage, + &compile_flags, + None, + &[], + ); + + let (result, log_level) = match compiled { + Ok(dxc_result) => match dxc_result.get_result() { + Ok(dxc_blob) => ( + Ok(crate::dx12::CompiledShader::Dxc(dxc_blob.to_vec())), + log::Level::Info, + ), + Err(e) => ( + Err(crate::PipelineError::Linkage( + stage_bit, + format!("DXC compile error: {}", e), + )), + log::Level::Error, + ), + }, + Err(e) => ( + Err(crate::PipelineError::Linkage( + stage_bit, + format!("DXC compile error: {:?}", e), + )), + log::Level::Error, + ), + }; + + (result, log_level) + } + + impl From for crate::DeviceError { + fn from(value: hassle_rs::HassleError) -> Self { + match value { + hassle_rs::HassleError::Win32Error(e) => { + // TODO: This returns an HRESULT, should we try and use the associated Windows error message? + log::error!("Win32 error: {e:?}"); + crate::DeviceError::Lost + } + hassle_rs::HassleError::LoadLibraryError { filename, inner } => { + log::error!("Failed to load dxc library {filename:?}. Inner error: {inner:?}"); + crate::DeviceError::Lost + } + hassle_rs::HassleError::LibLoadingError(e) => { + log::error!("Failed to load dxc library. {e:?}"); + crate::DeviceError::Lost + } + hassle_rs::HassleError::WindowsOnly(e) => { + log::error!("Signing with dxil.dll is only supported on Windows. {e:?}"); + crate::DeviceError::Lost + } + // `ValidationError` and `CompileError` should never happen in a context involving `DeviceError` + hassle_rs::HassleError::ValidationError(_e) => unimplemented!(), + hassle_rs::HassleError::CompileError(_e) => unimplemented!(), + } + } + } +} + +// These are stubs for when the `dxc_shader_compiler` feature is disabled. +#[cfg(not(feature = "dxc_shader_compiler"))] +mod dxc { + use std::path::PathBuf; + + pub(crate) struct DxcContainer {} + + pub(crate) fn get_dxc_container( + _dxc_path: Option, + _dxil_path: Option, + ) -> Result, crate::DeviceError> { + // Falls back to Fxc and logs an error. + log::error!("DXC shader compiler was requested on Instance creation, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC."); + Ok(None) + } + + // It shouldn't be possible that this gets called with the `dxc_shader_compiler` feature disabled. + pub(crate) fn compile_dxc( + _device: &crate::dx12::Device, + _source: &str, + _source_name: &str, + _raw_ep: &str, + _stage_bit: wgt::ShaderStages, + _full_stage: String, + _dxc_container: &DxcContainer, + ) -> ( + Result, + log::Level, + ) { + unimplemented!("Something went really wrong, please report this. Attempted to compile shader with DXC, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC."); + } +} diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index f20aa89a1f..2654bddc0c 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -743,6 +743,7 @@ bitflags::bitflags! { pub struct InstanceDescriptor<'a> { pub name: &'a str, pub flags: InstanceFlags, + pub dx12_shader_compiler: wgt::Dx12Compiler, } #[derive(Clone, Debug)] diff --git a/wgpu-info/src/main.rs b/wgpu-info/src/main.rs index cb1cbb3f96..4894e25e38 100644 --- a/wgpu-info/src/main.rs +++ b/wgpu-info/src/main.rs @@ -281,7 +281,7 @@ mod inner { env_logger::init(); let args: Vec<_> = std::env::args().skip(1).collect(); - let instance = wgpu::Instance::new(wgpu::Backends::all()); + let instance = wgpu::Instance::default(); let adapters: Vec<_> = instance.enumerate_adapters(wgpu::Backends::all()).collect(); let adapter_count = adapters.len(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 57b12e8c2b..0e9fee6fa8 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -12,6 +12,7 @@ #[cfg(any(feature = "serde", test))] use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; +use std::path::PathBuf; use std::{num::NonZeroU32, ops::Range}; pub mod assertions; @@ -5362,3 +5363,50 @@ impl Default for ShaderBoundChecks { Self::new() } } + +/// Selects which DX12 shader compiler to use. +/// +/// If the `wgpu-hal/dx12-shader-compiler` feature isn't enabled then this will fall back +/// to the Fxc compiler at runtime and log an error. +/// This feature is always enabled when using `wgpu`. +/// +/// If the `Dxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found, +/// then this will fall back to the Fxc compiler at runtime and log an error. +/// +/// `wgpu::utils::init::dx12_shader_compiler_from_env` can be used to set the compiler +/// from the `WGPU_DX12_SHADER_COMPILER` environment variable, but this should only be used for testing. +#[derive(Clone, Debug, Default)] +pub enum Dx12Compiler { + /// The Fxc compiler (default) is old, slow and unmaintained. + /// + /// However, it doesn't require any additional .dlls to be shipped with the application. + #[default] + Fxc, + /// The Dxc compiler is new, fast and maintained. + /// + /// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application. + /// These files can be downloaded from https://github.com/microsoft/DirectXShaderCompiler/releases + Dxc { + /// Path to the `dxcompiler.dll` file. Passing `None` will use standard platform specific dll loading rules. + dxil_path: Option, + /// Path to the `dxil.dll` file. Passing `None` will use standard platform specific dll loading rules. + dxc_path: Option, + }, +} + +/// Options for creating an instance. +pub struct InstanceDescriptor { + /// Which `Backends` to enable. + pub backends: Backends, + /// Which DX12 shader compiler to use. + pub dx12_shader_compiler: Dx12Compiler, +} + +impl Default for InstanceDescriptor { + fn default() -> Self { + Self { + backends: Backends::all(), + dx12_shader_compiler: Dx12Compiler::default(), + } + } +} diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 186202ea6c..f10f10b9d8 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -141,7 +141,7 @@ hal = { workspace = true } hal = { workspace = true, features = ["renderdoc"] } [target.'cfg(windows)'.dependencies] -hal = { workspace = true, features = ["renderdoc", "windows_rs"] } +hal = { workspace = true, features = ["dxc_shader_compiler", "renderdoc", "windows_rs"] } [target.'cfg(target_arch = "wasm32")'.dependencies.hal] workspace = true diff --git a/wgpu/examples/capture/main.rs b/wgpu/examples/capture/main.rs index 04a73f93ca..8fe95a06ad 100644 --- a/wgpu/examples/capture/main.rs +++ b/wgpu/examples/capture/main.rs @@ -36,12 +36,15 @@ async fn create_red_image_with_dimensions( width: usize, height: usize, ) -> (Device, Buffer, BufferDimensions, SubmissionIndex) { - let adapter = wgpu::Instance::new( - wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all), - ) - .request_adapter(&wgpu::RequestAdapterOptions::default()) - .await - .unwrap(); + let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends, + dx12_shader_compiler: wgpu::Dx12Compiler::default(), + }); + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions::default()) + .await + .unwrap(); let (device, queue) = adapter .request_device( diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 797b3c9ecd..f2d8e168fc 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -157,9 +157,13 @@ async fn setup(title: &str) -> Setup { log::info!("Initializing the surface..."); - let backend = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all); + let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all); + let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(); - let instance = wgpu::Instance::new(backend); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends, + dx12_shader_compiler, + }); let (size, surface) = unsafe { let size = window.inner_size(); @@ -180,7 +184,7 @@ async fn setup(title: &str) -> Setup { (size, surface) }; let adapter = - wgpu::util::initialize_adapter_from_env_or_default(&instance, backend, Some(&surface)) + wgpu::util::initialize_adapter_from_env_or_default(&instance, backends, Some(&surface)) .await .expect("No suitable GPU adapters found on the system!"); diff --git a/wgpu/examples/hello-compute/main.rs b/wgpu/examples/hello-compute/main.rs index 3e21ee11be..b46cabe06b 100644 --- a/wgpu/examples/hello-compute/main.rs +++ b/wgpu/examples/hello-compute/main.rs @@ -33,7 +33,7 @@ async fn run() { async fn execute_gpu(numbers: &[u32]) -> Option> { // Instantiates instance of WebGPU - let instance = wgpu::Instance::new(wgpu::Backends::all()); + let instance = wgpu::Instance::default(); // `request_adapter` instantiates the general connection to the GPU let adapter = instance diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index 58e7ba1a90..9b00992170 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -7,7 +7,9 @@ use winit::{ async fn run(event_loop: EventLoop<()>, window: Window) { let size = window.inner_size(); - let instance = wgpu::Instance::new(wgpu::Backends::all()); + + let instance = wgpu::Instance::default(); + let surface = unsafe { instance.create_surface(&window) }.unwrap(); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { diff --git a/wgpu/examples/hello-windows/main.rs b/wgpu/examples/hello-windows/main.rs index 4a93cf6b7f..df1057b27c 100644 --- a/wgpu/examples/hello-windows/main.rs +++ b/wgpu/examples/hello-windows/main.rs @@ -62,7 +62,7 @@ impl Viewport { } async fn run(event_loop: EventLoop<()>, viewports: Vec<(Window, wgpu::Color)>) { - let instance = wgpu::Instance::new(wgpu::Backends::all()); + let instance = wgpu::Instance::default(); let viewports: Vec<_> = viewports .into_iter() .map(|(window, color)| ViewportDesc::new(window, color, &instance)) diff --git a/wgpu/examples/hello/main.rs b/wgpu/examples/hello/main.rs index f74c5d1f8e..71d947cdc6 100644 --- a/wgpu/examples/hello/main.rs +++ b/wgpu/examples/hello/main.rs @@ -2,7 +2,7 @@ async fn run() { #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] let adapter = { - let instance = wgpu::Instance::new(wgpu::Backends::all()); + let instance = wgpu::Instance::default(); #[cfg(not(target_arch = "wasm32"))] { log::info!("Available adapters:"); diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 6d5a30ecfe..ce765bd492 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -511,11 +511,11 @@ impl crate::Context for Context { type PopErrorScopeFuture = Ready>; - fn init(backends: wgt::Backends) -> Self { + fn init(instance_desc: wgt::InstanceDescriptor) -> Self { Self(wgc::hub::Global::new( "wgpu", wgc::hub::IdentityManagerFactory, - backends, + instance_desc, )) } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 6ccab8df72..8bb7b5ad6c 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -805,7 +805,7 @@ impl crate::context::Context for Context { type PopErrorScopeFuture = MakeSendFuture Option>; - fn init(_backends: wgt::Backends) -> Self { + fn init(_instance_desc: wgt::InstanceDescriptor) -> Self { let global: Global = js_sys::global().unchecked_into(); let gpu = if !global.window().is_undefined() { global.unchecked_into::().navigator().gpu() diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index b915edf7ba..6ebc516d0f 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -95,7 +95,7 @@ pub trait Context: Debug + Send + Sized + Sync { + 'static; type PopErrorScopeFuture: Future> + Send + 'static; - fn init(backends: wgt::Backends) -> Self; + fn init(instance_desc: wgt::InstanceDescriptor) -> Self; fn instance_create_surface( &self, display_handle: raw_window_handle::RawDisplayHandle, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 73def3302f..bb2e0088bb 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -33,18 +33,18 @@ pub use wgt::{ BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, DepthBiasState, - DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, DynamicOffset, Extent3d, - Face, Features, FilterMode, FrontFace, ImageDataLayout, ImageSubresourceRange, IndexFormat, - Limits, MultisampleState, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, - PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, PushConstantRange, - QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation, - ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState, - StorageTextureAccess, SurfaceCapabilities, SurfaceConfiguration, SurfaceStatus, TextureAspect, - TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, - TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, - VertexStepMode, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, - PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, - VERTEX_STRIDE_ALIGNMENT, + DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, Dx12Compiler, + DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, ImageDataLayout, + ImageSubresourceRange, IndexFormat, InstanceDescriptor, Limits, MultisampleState, Origin3d, + PipelineStatisticsTypes, PolygonMode, PowerPreference, PresentMode, PresentationTimestamp, + PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, + SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, + StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, + SurfaceConfiguration, SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, + TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, + TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, + QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; /// Filter for error scopes. @@ -1286,16 +1286,25 @@ impl Display for SurfaceError { impl error::Error for SurfaceError {} +impl Default for Instance { + /// Creates a new instance of wgpu with default options. + /// + /// Backends are set to `Backends::all()`, and FXC is chosen as the `dx12_shader_compiler`. + fn default() -> Self { + Self::new(InstanceDescriptor::default()) + } +} + impl Instance { /// Create an new instance of wgpu. /// /// # Arguments /// - /// - `backends` - Controls from which [backends][Backends] wgpu will choose - /// during instantiation. - pub fn new(backends: Backends) -> Self { + /// - `instance_desc` - Has fields for which [backends][Backends] wgpu will choose + /// during instantiation, and which [DX12 shader compiler][Dx12Compiler] wgpu will use. + pub fn new(instance_desc: InstanceDescriptor) -> Self { Self { - context: Arc::from(crate::backend::Context::init(backends)), + context: Arc::from(crate::backend::Context::init(instance_desc)), } } diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index 7f442332dc..d5c7c6ad47 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -86,3 +86,23 @@ pub async fn initialize_adapter_from_env_or_default( } } } + +/// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`. +/// +/// Possible values are `dxc` and `fxc`. Case insensitive. +pub fn dx12_shader_compiler_from_env() -> Option { + Some( + match std::env::var("WGPU_DX12_COMPILER") + .as_deref() + .map(str::to_lowercase) + .as_deref() + { + Ok("dxc") => wgt::Dx12Compiler::Dxc { + dxil_path: None, + dxc_path: None, + }, + Ok("fxc") => wgt::Dx12Compiler::Fxc, + _ => return None, + }, + ) +} diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index cdcf8f94ea..1aa54fa0b8 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -331,8 +331,12 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te } fn initialize_adapter() -> (Adapter, SurfaceGuard) { - let backend_bits = wgpu::util::backend_bits_from_env().unwrap_or_else(Backends::all); - let instance = Instance::new(backend_bits); + let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(Backends::all); + let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(); + let instance = Instance::new(wgpu::InstanceDescriptor { + backends, + dx12_shader_compiler, + }); let surface_guard; let compatible_surface; @@ -358,7 +362,7 @@ fn initialize_adapter() -> (Adapter, SurfaceGuard) { let compatible_surface: Option<&Surface> = compatible_surface.as_ref(); let adapter = pollster::block_on(wgpu::util::initialize_adapter_from_env_or_default( &instance, - backend_bits, + backends, compatible_surface, )) .expect("could not find suitable adapter on the system"); diff --git a/wgpu/tests/instance.rs b/wgpu/tests/instance.rs index 1ead17c57e..e9ff6afff0 100644 --- a/wgpu/tests/instance.rs +++ b/wgpu/tests/instance.rs @@ -3,15 +3,17 @@ use wasm_bindgen_test::*; #[test] #[wasm_bindgen_test] fn initialize() { - let _ = wgpu::Instance::new( - wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all), - ); + let _ = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all), + dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), + }); } fn request_adapter_inner(power: wgt::PowerPreference) { - let instance = wgpu::Instance::new( - wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all), - ); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all), + dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), + }); let _adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { power_preference: power,