Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Dxc integration for DX12 backend #3356

Merged
merged 33 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
99aa681
DXC Integration in DX12 Backend
39ali Oct 29, 2022
c3d3dba
Added DXC compile flags
39ali Oct 29, 2022
402c611
Replaced `and` with `and_then` so that `hassle_rs::compile_hlsl` isn'…
39ali Nov 1, 2022
85cfc38
Fixed clippy warnings
39ali Nov 3, 2022
b41a662
why doesn't this work...
Elabajaba Jan 5, 2023
49fb214
error handling
Elabajaba Jan 5, 2023
f0a426a
store dxc related stuff in `DxcContainer` to make it work
Elabajaba Jan 5, 2023
de254f4
clippy
Elabajaba Jan 6, 2023
f31917c
Rename ShaderDXIL to CompiledShader, don't re-validate/re-sign after …
Elabajaba Jan 6, 2023
2145dfd
arrayvec and clippy
Elabajaba Jan 6, 2023
89b76b5
add dx12compiler option to Instance::new()
Elabajaba Jan 11, 2023
c2bdc39
use InstanceOptions struct when creating an Instance
Elabajaba Jan 11, 2023
02617bb
Move dx12 shader compilation to a separate file and put hassle-rs beh…
Elabajaba Jan 11, 2023
e4e6622
clippy
Elabajaba Jan 11, 2023
124f2bd
docs and minor cleanup
Elabajaba Jan 12, 2023
84584e2
use InstanceOptions instead of Backends for web init
Elabajaba Jan 12, 2023
50d8479
unwrap_or_default()
Elabajaba Jan 12, 2023
1313757
fmt
Elabajaba Jan 12, 2023
21f04c8
Link to where to download the .dlls from Microsoft
Elabajaba Jan 12, 2023
1fde6fc
derive default for enum
Elabajaba Jan 12, 2023
7034749
more docs
Elabajaba Jan 12, 2023
c2e43f2
changelog
Elabajaba Jan 12, 2023
11835ac
changelog
Elabajaba Jan 12, 2023
ecf46bc
misc cleanup
Elabajaba Jan 12, 2023
458eb8f
Replace compile_dxc stub fallback with unimplemented!() as it is defi…
Elabajaba Jan 12, 2023
6d01198
document `WGPU_DX12_COMPILER` in the readme
Elabajaba Jan 13, 2023
879adb8
move shader compilation profiling to the functions where it happens
Elabajaba Jan 13, 2023
dbc1dc9
add CompiledShader helpers
Elabajaba Jan 13, 2023
b90908f
rename `shader` mod to `dxc`
Elabajaba Jan 13, 2023
221db56
remove InstanceOptions::new(...) in favour of using the struct
Elabajaba Jan 13, 2023
37e60b4
misc cleanup
Elabajaba Jan 13, 2023
84f19c2
rename InstanceOptions to InstanceDescriptor, dx12_shader_compiler is…
Elabajaba Jan 16, 2023
2048c27
Merge branch 'master' into dxc-integration
cwfitzgerald Jan 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
3 changes: 2 additions & 1 deletion wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ metal = ["naga/msl-out", "block", "foreign-types"]
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "smallvec"]
gles = ["naga/glsl-out", "glow", "egl", "libloading"]
dx11 = ["naga/hlsl-out", "native", "libloading", "winapi/d3d11", "winapi/d3d11_1", "winapi/d3d11_2", "winapi/d3d11sdklayers", "winapi/dxgi1_6"]
dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6", "hassle-rs"]
# 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"]
renderdoc = ["libloading", "renderdoc-sys"]
Expand Down Expand Up @@ -75,6 +75,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
202 changes: 162 additions & 40 deletions wgpu-hal/src/dx12/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ impl super::Device {
) -> Result<Self, crate::DeviceError> {
let mem_allocator = super::suballocation::create_allocator_wrapper(&raw)?;

// TODO: path to dxcompiler.dll and dxil.dll should be configurable
// TODO: handle this not existing
let dxc_container = if true {
let dxc = hassle_rs::Dxc::new(Some("./".into()))?;
let dxc_compiler = dxc.create_compiler()?;
let dxc_library = dxc.create_library()?;
// Make sure that dxil.dll exists.
let _ = hassle_rs::Dxil::new(Some("./".into()))?;

Some(super::DxcContainer {
_dxc: dxc,
dxc_compiler,
dxc_library,
})
} else {
None
};

let mut idle_fence = native::Fence::null();
let hr = unsafe {
profiling::scope!("ID3D12Device::CreateFence");
Expand Down Expand Up @@ -166,6 +184,7 @@ impl super::Device {
render_doc: Default::default(),
null_rtv_handle,
mem_allocator,
dxc_container,
})
}

Expand All @@ -192,7 +211,7 @@ impl super::Device {
stage: &crate::ProgrammableStage<super::Api>,
layout: &super::PipelineLayout,
naga_stage: naga::ShaderStage,
) -> Result<native::Blob, crate::PipelineError> {
) -> Result<super::CompiledShader, crate::PipelineError> {
use naga::back::hlsl;

let stage_bit = crate::auxil::map_naga_stage(naga_stage);
Expand All @@ -212,18 +231,114 @@ 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 source_name = stage
.module
.raw_name
.as_ref()
.and_then(|cstr| cstr.to_str().ok())
.unwrap_or_default();

// Compile with DXC if available, otherwise fall back to FXC
let (result, log_level) = if let Some(ref dxc_container) = self.dxc_container {
profiling::scope!("hassle_rs::compile_hlsl");
let mut compile_flags = arrayvec::ArrayVec::<&str, 3>::new_const();
compile_flags.push("-Ges"); // d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS
if self
.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 = dxc_container
.dxc_library
.create_blob_with_encoding_from_str(&source)
.map_err(|e| {
crate::PipelineError::Linkage(stage_bit, format!("DXC blob error: {}", e))
})?;

let compiled = dxc_container.dxc_compiler.compile(
&blob,
source_name,
raw_ep,
&full_stage,
&compile_flags,
None, // TODO: idk what the include handler does
&[],
);

let (result, log_level) = match compiled {
Ok(dxc_result) => match dxc_result.get_result() {
Ok(dxc_blob) => (
Ok(super::CompiledShader::Dxc(dxc_blob.to_vec())),
log::Level::Info,
),
Err(e) => (
Err(crate::PipelineError::Linkage(
stage_bit,
format!("DXC compile error: {}", e),
)),
log::Level::Warn,
),
},
Err(e) => (
Err(crate::PipelineError::Linkage(
stage_bit,
format!("DXC compile error: {:?}", e),
)),
log::Level::Warn,
),
};

(result, log_level)
} else {
profiling::scope!("wgpu::backend::directx12::compile_fxc");
let (fxc_result, log_level) = self.compile_fxc(
&source,
source_name,
&ffi::CString::new(raw_ep.as_str()).unwrap(),
stage_bit,
full_stage,
);
(fxc_result, log_level)
};

log::log!(
log_level,
"Naga generated shader for {:?} at {:?}:\n{}",
raw_ep,
naga_stage,
source
);
result
}

// This function gets called if `device::dxc_compiler` is None, or if TODO: flag is set that disables DXC.
fn compile_fxc(
&self,
source: &String,
source_name: &str,
raw_ep: &ffi::CString,
stage_bit: wgt::ShaderStages,
full_stage: String,
) -> (
Result<super::CompiledShader, crate::PipelineError>,
log::Level,
) {
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
Expand All @@ -233,33 +348,31 @@ impl super::Device {
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 mut error = native::Blob::null();
let hr = unsafe {
profiling::scope!("d3dcompiler::D3DCompile");
d3dcompiler::D3DCompile(
source.as_ptr() as *const _,
source.as_ptr().cast(),
source.len(),
source_name,
source_name.as_ptr().cast(),
ptr::null(),
ptr::null_mut(),
raw_ep.as_ptr(),
full_stage.as_ptr() as *const i8,
full_stage.as_ptr().cast(),
compile_flags,
0,
shader_data.mut_void() as *mut *mut _,
error.mut_void() as *mut *mut _,
shader_data.mut_void().cast(),
error.mut_void().cast(),
)
};

let (result, log_level) = match hr.into_result() {
Ok(()) => (Ok(shader_data), log::Level::Info),
match hr.into_result() {
Ok(()) => (
Ok(super::CompiledShader::Fxc(shader_data)),
log::Level::Info,
),
Err(e) => {
let mut full_msg = format!("D3DCompile error ({})", e);
let mut full_msg = format!("FXC D3DCompile error ({})", e);
if !error.is_null() {
use std::fmt::Write as _;
let message = unsafe {
Expand All @@ -278,16 +391,7 @@ impl super::Device {
log::Level::Warn,
)
}
};

log::log!(
log_level,
"Naga generated shader for {:?} at {:?}:\n{}",
raw_ep,
naga_stage,
source
);
result
}
}

pub fn raw_device(&self) -> &native::Device {
Expand Down Expand Up @@ -1078,7 +1182,12 @@ impl crate::Device<super::Api> 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,
Expand Down Expand Up @@ -1294,9 +1403,9 @@ impl crate::Device<super::Api> 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];
Expand Down Expand Up @@ -1369,11 +1478,14 @@ impl crate::Device<super::Api> 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: match blob_vs {
super::CompiledShader::Dxc(ref blob_vs) => *native::Shader::from_raw(blob_vs),
super::CompiledShader::Fxc(blob_vs) => *native::Shader::from_blob(blob_vs),
},
Elabajaba marked this conversation as resolved.
Show resolved Hide resolved
PS: match blob_fs {
Some(super::CompiledShader::Dxc(ref blob_fs)) => *native::Shader::from_raw(blob_fs),
Some(super::CompiledShader::Fxc(blob_fs)) => *native::Shader::from_blob(blob_fs),
None => *native::Shader::null(),
},
GS: *native::Shader::null(),
DS: *native::Shader::null(),
Expand Down Expand Up @@ -1444,9 +1556,12 @@ impl crate::Device<super::Api> for super::Device {
}
};

unsafe { blob_vs.destroy() };
if !blob_fs.is_null() {
unsafe { blob_fs.destroy() };
if let super::CompiledShader::Fxc(ref vs_fxc) = blob_vs {
unsafe { vs_fxc.destroy() };
}

if let Some(super::CompiledShader::Fxc(ref fs_fxc)) = blob_fs {
unsafe { fs_fxc.destroy() };
}
Elabajaba marked this conversation as resolved.
Show resolved Hide resolved

hr.into_result()
Expand Down Expand Up @@ -1478,14 +1593,21 @@ impl crate::Device<super::Api> for super::Device {
profiling::scope!("ID3D12Device::CreateComputePipelineState");
self.raw.create_compute_pipeline_state(
desc.layout.shared.signature,
native::Shader::from_blob(blob_cs),
match blob_cs {
crate::dx12::CompiledShader::Dxc(ref blob_cs) => {
native::Shader::from_raw(blob_cs)
}
crate::dx12::CompiledShader::Fxc(blob_cs) => native::Shader::from_blob(blob_cs),
},
0,
native::CachedPSO::null(),
native::PipelineStateFlags::empty(),
)
};

unsafe { blob_cs.destroy() };
if let super::CompiledShader::Fxc(cs_fxc) = blob_cs {
unsafe { cs_fxc.destroy() };
}

let raw = pair.into_result().map_err(|err| {
crate::PipelineError::Linkage(wgt::ShaderStages::COMPUTE, err.into_owned())
Expand Down
Loading