[d3d12] make DxgiLib and D3D12Lib methods consistent

This commit is contained in:
teoxoy 2024-08-21 15:10:48 +02:00 committed by Teodor Tanasoaia
parent 29e288f81c
commit dd01b6d209
5 changed files with 119 additions and 134 deletions

View File

@ -225,18 +225,8 @@ pub fn create_factory(
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
// `CreateDXGIFactory2` if the debug interface is actually available. So
// we check for whether it exists first.
match lib_dxgi.debug_interface1() {
Ok(pair) => match pair {
Ok(_debug_controller) => {
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
}
Err(err) => {
log::warn!("Unable to enable DXGI debug interface: {}", err);
}
},
Err(err) => {
log::warn!("Debug interface function for DXGI not found: {:?}", err);
}
if lib_dxgi.debug_interface1().is_ok() {
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
}
// Intercept `OutputDebugString` calls
@ -244,27 +234,18 @@ pub fn create_factory(
}
// Try to create IDXGIFactory4
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
Ok(pair) => match pair {
Ok(factory) => Some(factory),
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
Err(err) => {
// err is a Cow<str>, not an Error implementor
return Err(crate::InstanceError::new(format!(
"failed to create IDXGIFactory4: {err:?}"
)));
}
},
let factory4 = match lib_dxgi.create_factory4(factory_flags) {
Ok(factory) => Some(factory),
// If we require factory4, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory4 => {
return Err(crate::InstanceError::with_source(
String::from("IDXGIFactory1 creation function not found"),
String::from("IDXGIFactory4 creation failed"),
err,
));
}
// If we don't print it to warn as all win7 will hit this case.
Err(err) => {
log::warn!("IDXGIFactory1 creation function not found: {err:?}");
log::warn!("IDXGIFactory4 creation function not found: {err:?}");
None
}
};
@ -293,19 +274,10 @@ pub fn create_factory(
// Try to create IDXGIFactory1
let factory1 = match lib_dxgi.create_factory1() {
Ok(pair) => match pair {
Ok(factory) => factory,
Err(err) => {
// err is a Cow<str>, not an Error implementor
return Err(crate::InstanceError::new(format!(
"failed to create IDXGIFactory1: {err:?}"
)));
}
},
// We always require at least factory1, so hard error
Ok(factory) => factory,
Err(err) => {
return Err(crate::InstanceError::with_source(
String::from("IDXGIFactory1 creation function not found"),
String::from("IDXGIFactory1 creation failed"),
err,
));
}

View File

@ -64,19 +64,9 @@ impl super::Adapter {
// Create the device so that we can get the capabilities.
let device = {
profiling::scope!("ID3D12Device::create_device");
match library.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) {
Ok(pair) => match pair {
Ok(device) => device,
Err(err) => {
log::warn!("Device creation failed: {}", err);
return None;
}
},
Err(err) => {
log::warn!("Device creation function is not found: {:?}", err);
return None;
}
}
library
.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0)
.ok()?
};
profiling::scope!("feature queries");

View File

@ -34,31 +34,20 @@ impl crate::Instance for super::Instance {
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
// Enable debug layer
match lib_main.debug_interface() {
Ok(pair) => match pair {
Ok(debug_controller) => {
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
unsafe { debug_controller.EnableDebugLayer() }
}
if desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
#[allow(clippy::collapsible_if)]
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>()
{
unsafe { debug1.SetEnableGPUBasedValidation(true) }
} else {
log::warn!("Failed to enable GPU-based validation");
}
}
if let Ok(debug_controller) = lib_main.debug_interface() {
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
unsafe { debug_controller.EnableDebugLayer() }
}
if desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
#[allow(clippy::collapsible_if)]
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>() {
unsafe { debug1.SetEnableGPUBasedValidation(true) }
} else {
log::warn!("Failed to enable GPU-based validation");
}
Err(err) => {
log::warn!("Unable to enable D3D12 debug interface: {}", err);
}
},
Err(err) => {
log::warn!("Debug interface function for D3D12 not found: {:?}", err);
}
}
}
@ -70,19 +59,7 @@ impl crate::Instance for super::Instance {
)?;
// Create IDXGIFactoryMedia
let factory_media = match lib_dxgi.create_factory_media() {
Ok(pair) => match pair {
Ok(factory_media) => Some(factory_media),
Err(err) => {
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
None
}
},
Err(err) => {
log::warn!("IDXGIFactory1 creation function not found: {:?}", err);
None
}
};
let factory_media = lib_dxgi.create_factory_media().ok();
let mut supports_allow_tearing = false;
if let Some(factory5) = factory.as_factory5() {

View File

@ -65,21 +65,47 @@ use crate::auxil::{
},
};
#[derive(Debug)]
struct DynLib {
inner: libloading::Library,
}
impl DynLib {
unsafe fn new(filename: &'static str) -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new(filename) }.map(|inner| Self { inner })
}
unsafe fn get<T>(
&self,
symbol: &[u8],
) -> Result<libloading::Symbol<'_, T>, crate::DeviceError> {
unsafe { self.inner.get(symbol) }.map_err(|e| match e {
libloading::Error::GetProcAddress { .. } | libloading::Error::GetProcAddressUnknown => {
crate::DeviceError::Unexpected
}
libloading::Error::IncompatibleSize
| libloading::Error::CreateCString { .. }
| libloading::Error::CreateCStringWithTrailing { .. } => crate::hal_internal_error(e),
_ => crate::DeviceError::Unexpected, // could be unreachable!() but we prefer to be more robust
})
}
}
#[derive(Debug)]
struct D3D12Lib {
lib: libloading::Library,
lib: DynLib,
}
impl D3D12Lib {
fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) }
unsafe { DynLib::new("d3d12.dll").map(|lib| Self { lib }) }
}
fn create_device(
&self,
adapter: &DxgiAdapter,
feature_level: Direct3D::D3D_FEATURE_LEVEL,
) -> Result<windows_core::Result<Direct3D12::ID3D12Device>, libloading::Error> {
) -> Result<Direct3D12::ID3D12Device, crate::DeviceError> {
// Calls windows::Win32::Graphics::Direct3D12::D3D12CreateDevice on d3d12.dll
type Fun = extern "system" fn(
padapter: *mut core::ffi::c_void,
@ -90,14 +116,18 @@ impl D3D12Lib {
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12CreateDevice") }?;
let mut result__ = None;
Ok((func)(
(func)(
unsafe { adapter.param().abi() },
feature_level,
// TODO: Generic?
&Direct3D12::ID3D12Device::IID,
<*mut _>::cast(&mut result__),
)
.map(|| result__.expect("D3D12CreateDevice succeeded but result is NULL?")))
.ok()
.into_device_result("Device creation")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
fn serialize_root_signature(
@ -114,11 +144,8 @@ impl D3D12Lib {
ppblob: *mut *mut core::ffi::c_void,
pperrorblob: *mut *mut core::ffi::c_void,
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12SerializeRootSignature") }
.map_err(|e| {
log::error!("Unable to find serialization function: {:?}", e);
crate::DeviceError::Lost
})?;
let func: libloading::Symbol<Fun> =
unsafe { self.lib.get(b"D3D12SerializeRootSignature") }?;
let desc = Direct3D12::D3D12_ROOT_SIGNATURE_DESC {
NumParameters: parameters.len() as _,
@ -137,8 +164,6 @@ impl D3D12Lib {
<*mut _>::cast(&mut error),
)
.ok()
// TODO: If there's a HRESULT, error may still be non-null and
// contain info.
.into_device_result("Root signature serialization")?;
if let Some(error) = error {
@ -147,17 +172,13 @@ impl D3D12Lib {
"Root signature serialization error: {:?}",
unsafe { error.as_c_str() }.unwrap().to_str().unwrap()
);
return Err(crate::DeviceError::Lost);
return Err(crate::DeviceError::Unexpected); // could be hal_usage_error or hal_internal_error
}
Ok(D3DBlob(blob.expect(
"D3D12SerializeRootSignature succeeded but result is NULL?",
)))
blob.ok_or(crate::DeviceError::Unexpected)
}
fn debug_interface(
&self,
) -> Result<windows::core::Result<Direct3D12::ID3D12Debug>, libloading::Error> {
fn debug_interface(&self) -> Result<Direct3D12::ID3D12Debug, crate::DeviceError> {
// Calls windows::Win32::Graphics::Direct3D12::D3D12GetDebugInterface on d3d12.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
@ -165,25 +186,28 @@ impl D3D12Lib {
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12GetDebugInterface") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(&Direct3D12::ID3D12Debug::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
let mut result__ = None;
(func)(&Direct3D12::ID3D12Debug::IID, <*mut _>::cast(&mut result__))
.ok()
.into_device_result("GetDebugInterface")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
}
#[derive(Debug)]
pub(super) struct DxgiLib {
lib: libloading::Library,
lib: DynLib,
}
impl DxgiLib {
pub fn new() -> Result<Self, libloading::Error> {
unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) }
unsafe { DynLib::new("dxgi.dll").map(|lib| Self { lib }) }
}
pub fn debug_interface1(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIInfoQueue>, libloading::Error> {
/// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available.
pub fn debug_interface1(&self) -> Result<Dxgi::IDXGIInfoQueue, crate::DeviceError> {
// Calls windows::Win32::Graphics::Dxgi::DXGIGetDebugInterface1 on dxgi.dll
type Fun = extern "system" fn(
flags: u32,
@ -192,14 +216,16 @@ impl DxgiLib {
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DXGIGetDebugInterface1") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(0, &Dxgi::IDXGIInfoQueue::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
let mut result__ = None;
(func)(0, &Dxgi::IDXGIInfoQueue::IID, <*mut _>::cast(&mut result__))
.ok()
.into_device_result("debug_interface1")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
pub fn create_factory1(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIFactory1>, libloading::Error> {
pub fn create_factory1(&self) -> Result<Dxgi::IDXGIFactory1, crate::DeviceError> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
@ -207,15 +233,20 @@ impl DxgiLib {
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
let mut result__ = core::ptr::null_mut();
Ok((func)(&Dxgi::IDXGIFactory1::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
let mut result__ = None;
(func)(&Dxgi::IDXGIFactory1::IID, <*mut _>::cast(&mut result__))
.ok()
.into_device_result("create_factory1")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
pub fn create_factory2(
/// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available.
pub fn create_factory4(
&self,
factory_flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
) -> Result<windows::core::Result<Dxgi::IDXGIFactory4>, libloading::Error> {
) -> Result<Dxgi::IDXGIFactory4, crate::DeviceError> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory2 on dxgi.dll
type Fun = extern "system" fn(
flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
@ -224,16 +255,21 @@ impl DxgiLib {
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory2") }?;
let mut result__ = core::ptr::null_mut();
Ok(
(func)(factory_flags, &Dxgi::IDXGIFactory4::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }),
let mut result__ = None;
(func)(
factory_flags,
&Dxgi::IDXGIFactory4::IID,
<*mut _>::cast(&mut result__),
)
.ok()
.into_device_result("create_factory4")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
pub fn create_factory_media(
&self,
) -> Result<windows::core::Result<Dxgi::IDXGIFactoryMedia>, libloading::Error> {
/// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available.
pub fn create_factory_media(&self) -> Result<Dxgi::IDXGIFactoryMedia, crate::DeviceError> {
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
type Fun = extern "system" fn(
riid: *const windows_core::GUID,
@ -241,10 +277,14 @@ impl DxgiLib {
) -> windows_core::HRESULT;
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
let mut result__ = core::ptr::null_mut();
let mut result__ = None;
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia
Ok((func)(&Dxgi::IDXGIFactoryMedia::IID, &mut result__)
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
(func)(&Dxgi::IDXGIFactoryMedia::IID, <*mut _>::cast(&mut result__))
.ok()
.into_device_result("create_factory_media")?;
result__.ok_or(crate::DeviceError::Unexpected)
}
}

View File

@ -351,6 +351,12 @@ fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal invariant was violated (usage error): {txt}")
}
#[allow(dead_code)] // may be unused on some platforms
#[cold]
fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal ran into a preventable internal error: {txt}")
}
#[derive(Clone, Debug, Eq, PartialEq, Error)]
pub enum ShaderError {
#[error("Compilation failed: {0:?}")]