mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Add dependency on mach-dxcompiler-rs and support statically linking DXC
This commit is contained in:
parent
00a6032eb7
commit
61bfc96f40
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -1778,6 +1778,15 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach-dxcompiler-rs"
|
||||
version = "2023.12.14+0b7073b.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7857414cb65eb5f03cf0365ac801f089fdbfbb0c47f3f257941eda735aebdf"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@ -3692,6 +3701,7 @@ dependencies = [
|
||||
"libc",
|
||||
"libloading",
|
||||
"log",
|
||||
"mach-dxcompiler-rs",
|
||||
"metal",
|
||||
"naga",
|
||||
"ndk-sys",
|
||||
|
@ -149,6 +149,7 @@ gpu-descriptor = "0.3"
|
||||
bit-set = "0.8"
|
||||
gpu-allocator = { version = "0.27", default-features = false }
|
||||
range-alloc = "0.1"
|
||||
mach-dxcompiler-rs = { version = "2023.12.14+0b7073b.1", default-features = false }
|
||||
windows-core = { version = "0.58", default-features = false }
|
||||
|
||||
# Gles dependencies
|
||||
|
@ -91,6 +91,8 @@ dx12 = [
|
||||
"windows/Win32_System_Threading",
|
||||
"windows/Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
## Enables the static DXC compiler using the `mach-dxcompiler-rs` crate.
|
||||
mach-dxcompiler-rs = ["dep:mach-dxcompiler-rs"]
|
||||
renderdoc = ["dep:libloading", "dep:renderdoc-sys"]
|
||||
fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"]
|
||||
# Panic when running into an out-of-memory error (for debugging purposes).
|
||||
@ -158,6 +160,7 @@ windows = { workspace = true, optional = true }
|
||||
bit-set = { workspace = true, optional = true }
|
||||
range-alloc = { workspace = true, optional = true }
|
||||
gpu-allocator = { workspace = true, optional = true }
|
||||
mach-dxcompiler-rs = { workspace = true, optional = true }
|
||||
# For core macros. This crate is also reexported as windows::core.
|
||||
windows-core = { workspace = true, optional = true }
|
||||
|
||||
|
@ -80,10 +80,22 @@ impl crate::Instance for super::Instance {
|
||||
dxil_path,
|
||||
dxc_path,
|
||||
} => {
|
||||
let container = super::shader_compilation::get_dxc_container(dxc_path, dxil_path)
|
||||
.map_err(|e| {
|
||||
crate::InstanceError::with_source(String::from("Failed to load DXC"), e)
|
||||
})?;
|
||||
let container =
|
||||
super::shader_compilation::get_dynamic_dxc_container(dxc_path, dxil_path)
|
||||
.map_err(|e| {
|
||||
crate::InstanceError::with_source(String::from("Failed to load DXC"), e)
|
||||
})?;
|
||||
|
||||
container.map(Arc::new)
|
||||
}
|
||||
wgt::Dx12Compiler::MachDxc => {
|
||||
let container =
|
||||
super::shader_compilation::get_mach_dxc_container().map_err(|e| {
|
||||
crate::InstanceError::with_source(
|
||||
String::from("Failed to load Mach DXC"),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
container.map(Arc::new)
|
||||
}
|
||||
|
@ -78,6 +78,12 @@ pub(super) fn compile_fxc(
|
||||
}
|
||||
}
|
||||
|
||||
type DxcCreateInstanceFn = unsafe extern "system" fn(
|
||||
rclsid: *const windows_core::GUID,
|
||||
riid: *const windows_core::GUID,
|
||||
ppv: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
|
||||
trait DxcObj: Interface {
|
||||
const CLSID: windows::core::GUID;
|
||||
}
|
||||
@ -97,7 +103,10 @@ struct DxcLib {
|
||||
}
|
||||
|
||||
impl DxcLib {
|
||||
fn new(lib_path: Option<PathBuf>, lib_name: &'static str) -> Result<Self, libloading::Error> {
|
||||
fn new_dynamic(
|
||||
lib_path: Option<PathBuf>,
|
||||
lib_name: &'static str,
|
||||
) -> Result<Self, libloading::Error> {
|
||||
let lib_path = if let Some(lib_path) = lib_path {
|
||||
if lib_path.is_file() {
|
||||
lib_path
|
||||
@ -111,15 +120,19 @@ impl DxcLib {
|
||||
}
|
||||
|
||||
pub fn create_instance<T: DxcObj>(&self) -> Result<T, crate::DeviceError> {
|
||||
type Fun = extern "system" fn(
|
||||
rclsid: *const windows_core::GUID,
|
||||
riid: *const windows_core::GUID,
|
||||
ppv: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DxcCreateInstance\0") }?;
|
||||
unsafe {
|
||||
let func: libloading::Symbol<DxcCreateInstanceFn> =
|
||||
self.lib.get(b"DxcCreateInstance\0")?;
|
||||
dxc_create_instance::<T>(*func)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes the provided library function to create a DXC object.
|
||||
unsafe fn dxc_create_instance<T: DxcObj>(f: DxcCreateInstanceFn) -> Result<T, crate::DeviceError> {
|
||||
unsafe {
|
||||
let mut result__ = None;
|
||||
(func)(&T::CLSID, &T::IID, <*mut _>::cast(&mut result__))
|
||||
f(&T::CLSID, &T::IID, <*mut _>::cast(&mut result__))
|
||||
.ok()
|
||||
.into_device_result("DxcCreateInstance")?;
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
@ -130,18 +143,20 @@ impl DxcLib {
|
||||
pub(super) struct DxcContainer {
|
||||
compiler: Dxc::IDxcCompiler3,
|
||||
utils: Dxc::IDxcUtils,
|
||||
validator: Dxc::IDxcValidator,
|
||||
validator: Option<Dxc::IDxcValidator>,
|
||||
// Has to be held onto for the lifetime of the device otherwise shaders will fail to compile.
|
||||
_dxc: DxcLib,
|
||||
// Only needed when using dynamic linking.
|
||||
_dxc: Option<DxcLib>,
|
||||
// Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate.
|
||||
_dxil: DxcLib,
|
||||
// Only needed when using dynamic linking.
|
||||
_dxil: Option<DxcLib>,
|
||||
}
|
||||
|
||||
pub(super) fn get_dxc_container(
|
||||
pub(super) fn get_dynamic_dxc_container(
|
||||
dxc_path: Option<PathBuf>,
|
||||
dxil_path: Option<PathBuf>,
|
||||
) -> Result<Option<DxcContainer>, crate::DeviceError> {
|
||||
let dxc = match DxcLib::new(dxc_path, "dxcompiler.dll") {
|
||||
let dxc = match DxcLib::new_dynamic(dxc_path, "dxcompiler.dll") {
|
||||
Ok(dxc) => dxc,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
@ -153,7 +168,7 @@ pub(super) fn get_dxc_container(
|
||||
}
|
||||
};
|
||||
|
||||
let dxil = match DxcLib::new(dxil_path, "dxil.dll") {
|
||||
let dxil = match DxcLib::new_dynamic(dxil_path, "dxil.dll") {
|
||||
Ok(dxil) => dxil,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
@ -172,12 +187,37 @@ pub(super) fn get_dxc_container(
|
||||
Ok(Some(DxcContainer {
|
||||
compiler,
|
||||
utils,
|
||||
validator,
|
||||
_dxc: dxc,
|
||||
_dxil: dxil,
|
||||
validator: Some(validator),
|
||||
_dxc: Some(dxc),
|
||||
_dxil: Some(dxil),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Creates a [`DxcContainer`] that delegates to the statically-linked `mach-dxcompiler` library.
|
||||
pub(super) fn get_mach_dxc_container() -> Result<Option<DxcContainer>, crate::DeviceError> {
|
||||
#[cfg(feature = "mach-dxcompiler-rs")]
|
||||
{
|
||||
unsafe {
|
||||
let compiler =
|
||||
dxc_create_instance::<Dxc::IDxcCompiler3>(mach_dxcompiler_rs::DxcCreateInstance)?;
|
||||
let utils =
|
||||
dxc_create_instance::<Dxc::IDxcUtils>(mach_dxcompiler_rs::DxcCreateInstance)?;
|
||||
|
||||
Ok(Some(DxcContainer {
|
||||
compiler,
|
||||
utils,
|
||||
validator: None,
|
||||
_dxc: None,
|
||||
_dxil: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "mach-dxcompiler-rs"))]
|
||||
{
|
||||
panic!("Attempted to create a Mach DXC shader compiler, but the mach-dxcompiler-rs feature was not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
/// Owned PCWSTR
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
struct OPCWSTR {
|
||||
@ -288,26 +328,24 @@ pub(super) fn compile_dxc(
|
||||
|
||||
let blob = get_output::<Dxc::IDxcBlob>(&compile_res, Dxc::DXC_OUT_OBJECT)?;
|
||||
|
||||
let err_blob = {
|
||||
let res = unsafe {
|
||||
dxc_container
|
||||
.validator
|
||||
.Validate(&blob, Dxc::DxcValidatorFlags_InPlaceEdit)
|
||||
if let Some(validator) = &dxc_container.validator {
|
||||
let err_blob = {
|
||||
let res = unsafe { validator.Validate(&blob, Dxc::DxcValidatorFlags_InPlaceEdit) }
|
||||
.into_device_result("Validate")?;
|
||||
|
||||
unsafe { res.GetErrorBuffer() }.into_device_result("GetErrorBuffer")?
|
||||
};
|
||||
|
||||
let size = unsafe { err_blob.GetBufferSize() };
|
||||
if size != 0 {
|
||||
let err_blob = unsafe { dxc_container.utils.GetBlobAsUtf8(&err_blob) }
|
||||
.into_device_result("GetBlobAsUtf8")?;
|
||||
let err = as_err_str(&err_blob)?;
|
||||
return Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!("DXC validation error: {err}"),
|
||||
));
|
||||
}
|
||||
.into_device_result("Validate")?;
|
||||
|
||||
unsafe { res.GetErrorBuffer() }.into_device_result("GetErrorBuffer")?
|
||||
};
|
||||
|
||||
let size = unsafe { err_blob.GetBufferSize() };
|
||||
if size != 0 {
|
||||
let err_blob = unsafe { dxc_container.utils.GetBlobAsUtf8(&err_blob) }
|
||||
.into_device_result("GetBlobAsUtf8")?;
|
||||
let err = as_err_str(&err_blob)?;
|
||||
return Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!("DXC validation error: {err}"),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(crate::dx12::CompiledShader::Dxc(blob))
|
||||
|
@ -7401,6 +7401,9 @@ pub enum Dx12Compiler {
|
||||
/// Path to the `dxcompiler.dll` file, or path to the directory containing `dxcompiler.dll` file. Passing `None` will use standard platform specific dll loading rules.
|
||||
dxc_path: Option<PathBuf>,
|
||||
},
|
||||
/// The statically-linked variant of Dxc, sourced from the [`mach-dxcompiler-rs`](https://crates.io/crates/mach-dxcompiler-rs) crate.
|
||||
/// The `mach-dxcompiler-rs` feature is required to use this.
|
||||
MachDxc,
|
||||
}
|
||||
|
||||
/// Selects which OpenGL ES 3 minor version to request.
|
||||
|
@ -73,6 +73,9 @@ glsl = ["naga/glsl-in", "wgc/glsl"]
|
||||
## Enable accepting WGSL shaders as input.
|
||||
wgsl = ["wgc?/wgsl"]
|
||||
|
||||
## Enables the static DXC compiler using the `mach-dxcompiler-rs` crate.
|
||||
mach-dxcompiler-rs = ["hal/mach-dxcompiler-rs"]
|
||||
|
||||
## Enable accepting naga IR shaders as input.
|
||||
naga-ir = ["dep:naga"]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user