Skip to content

Commit

Permalink
Updated Dxc integration for DX12 backend (#3356)
Browse files Browse the repository at this point in the history
Co-authored-by: unknown <alimilhim5@gmail.com>
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
Closes #2722
closes #3147
  • Loading branch information
Elabajaba committed Jan 18, 2023
1 parent 0849e78 commit 81569dd
Show file tree
Hide file tree
Showing 33 changed files with 593 additions and 127 deletions.
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,54 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non

`Instance::create_surface()` now returns `Result<Surface, CreateSurfaceError>` 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.
Expand Down
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
5 changes: 4 additions & 1 deletion deno_webgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Instance>()
};
Expand Down
6 changes: 5 additions & 1 deletion player/src/bin/play.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
9 changes: 8 additions & 1 deletion player/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions wgpu-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1108,10 +1108,10 @@ pub struct Global<G: GlobalIdentityHandlerFactory> {
}

impl<G: GlobalIdentityHandlerFactory> Global<G> {
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),
}
Expand Down
17 changes: 9 additions & 8 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ pub struct Instance {
}

impl Instance {
pub fn new(name: &str, backends: Backends) -> Self {
fn init<A: HalApi>(_: A, mask: Backends) -> Option<A::Instance> {
if mask.contains(A::VARIANT.into()) {
pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self {
fn init<A: HalApi>(_: A, instance_desc: &wgt::InstanceDescriptor) -> Option<A::Instance> {
if instance_desc.backends.contains(A::VARIANT.into()) {
let mut flags = hal::InstanceFlags::empty();
if cfg!(debug_assertions) {
flags |= hal::InstanceFlags::VALIDATION;
Expand All @@ -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 {
Expand All @@ -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),
}
}

Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/examples/halmark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl<A: hal::Api> Example<A> {
} 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 {
Expand Down
10 changes: 9 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl super::Adapter {
adapter: native::DxgiAdapter,
library: &Arc<native::D3D12Lib>,
instance_flags: crate::InstanceFlags,
dx12_shader_compiler: &wgt::Dx12Compiler,
) -> Option<crate::ExposedAdapter<super::Api>> {
// Create the device so that we can get the capabilities.
let device = {
Expand Down Expand Up @@ -243,6 +244,7 @@ impl super::Adapter {
private_caps,
presentation_timer,
workarounds,
dx12_shader_compiler: dx12_shader_compiler.clone(),
},
info,
features,
Expand Down Expand Up @@ -347,7 +349,13 @@ impl crate::Adapter<super::Api> 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 {
Expand Down
Loading

0 comments on commit 81569dd

Please sign in to comment.