Skip to content

Commit

Permalink
Factor out adapter enumeration
Browse files Browse the repository at this point in the history
  • Loading branch information
cwfitzgerald committed Mar 1, 2022
1 parent d2dfa50 commit 1ce3c63
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 95 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ default-members = ["wgpu", "wgpu-hal", "wgpu-info"]
[patch.crates-io]
#naga = { path = "../naga" }
#glow = { path = "../glow" }
d3d12 = { git = "https://github.com/cwfitzgerald/d3d12-rs.git", rev = "799c61f85c5fb8b1c6c8578973a384fbfe063af1" }
d3d12 = { git = "https://github.com/cwfitzgerald/d3d12-rs.git", rev = "0be1b3bc8ba3018a8994f7ebdf1fee8491920b93" }
# d3d12 = { path = "../d3d12-rs" }
#metal = { path = "../metal-rs" }
#web-sys = { path = "../wasm-bindgen/crates/web-sys" }
Expand Down
171 changes: 162 additions & 9 deletions wgpu-hal/src/auxil/dxgi/factory.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use winapi::shared::dxgi1_2;
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_4, dxgi1_5, dxgi1_6, winerror},
Interface,
};

use super::result::HResult as _;

Expand All @@ -7,26 +10,147 @@ pub enum DxgiFactoryType {
Factory1,
Factory2,
Factory4,
Factory6,
}

#[derive(Copy, Clone)]
pub enum DxgiFactory {
Factory1(native::Factory1),
Factory2(native::Factory2),
Factory4(native::Factory4),
Factory6(native::Factory6),
}

impl DxgiFactory {
pub fn destroy(&self) {
match *self {
DxgiFactory::Factory1(f) => unsafe { f.destroy() },
DxgiFactory::Factory2(f) => unsafe { f.destroy() },
DxgiFactory::Factory4(f) => unsafe { f.destroy() },
DxgiFactory::Factory6(f) => unsafe { f.destroy() },
}
}

#[track_caller]
pub fn as_factory6(self) -> Option<native::Factory6> {
match self {
DxgiFactory::Factory1(_) => None,
DxgiFactory::Factory2(_) => None,
DxgiFactory::Factory4(_) => None,
DxgiFactory::Factory6(f) => Some(f),
}
}

#[track_caller]
pub fn as_factory1(self) -> native::Factory1 {
match self {
DxgiFactory::Factory1(f) => f,
DxgiFactory::Factory2(f) => unsafe {
native::Factory1::from_raw(f.as_mut_ptr() as *mut dxgi::IDXGIFactory1)
},
DxgiFactory::Factory4(f) => unsafe {
native::Factory1::from_raw(f.as_mut_ptr() as *mut dxgi::IDXGIFactory1)
},
DxgiFactory::Factory6(f) => unsafe {
native::Factory1::from_raw(f.as_mut_ptr() as *mut dxgi::IDXGIFactory1)
},
}
}

#[track_caller]
pub fn as_factory2(self) -> Option<native::Factory2> {
match self {
DxgiFactory::Factory1(_) => None,
DxgiFactory::Factory2(f) => Some(f),
DxgiFactory::Factory4(f) => unsafe {
Some(native::Factory2::from_raw(
f.as_mut_ptr() as *mut dxgi1_2::IDXGIFactory2
))
},
DxgiFactory::Factory6(f) => unsafe {
Some(native::Factory2::from_raw(
f.as_mut_ptr() as *mut dxgi1_2::IDXGIFactory2
))
},
}
}

#[track_caller]
pub fn unwrap_factory4(self) -> native::Factory4 {
pub fn as_factory5(self) -> Option<native::WeakPtr<dxgi1_5::IDXGIFactory5>> {
match self {
DxgiFactory::Factory1(_) => panic!("unwrapping a factory4, got a factory1"),
DxgiFactory::Factory2(_) => panic!("unwrapping a factory4, got a factory2"),
DxgiFactory::Factory4(f) => f,
DxgiFactory::Factory1(_) => None,
DxgiFactory::Factory2(_) => None,
DxgiFactory::Factory4(_) => None,
DxgiFactory::Factory6(f) => unsafe {
Some(native::WeakPtr::from_raw(
f.as_mut_ptr() as *mut dxgi1_5::IDXGIFactory5
))
},
}
}

pub fn enumerate_adapters(&self) -> Vec<native::WeakPtr<dxgi1_2::IDXGIAdapter2>> {
let factory6 = self.as_factory6();

let mut adapters = Vec::with_capacity(8);

for cur_index in 0.. {
if let Some(factory) = factory6 {
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
let hr = unsafe {
factory.EnumAdapterByGpuPreference(
cur_index,
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&dxgi1_2::IDXGIAdapter2::uuidof(),
adapter2.mut_void(),
)
};

if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}

adapters.push(adapter2);
continue;
}

profiling::scope!("IDXGIFactory1::EnumAdapters1");
let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
let hr = unsafe {
self.as_factory1()
.EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _)
};

if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}

match unsafe { adapter1.cast::<dxgi1_2::IDXGIAdapter2>() }.into_result() {
Ok(adapter2) => {
unsafe { adapter1.destroy() };
adapters.push(adapter2);
}
Err(err) => {
log::error!("Failed casting Adapter1 to Adapter2: {}", err);
break;
}
}
}

adapters
}
}

/// Tries to create a IDXGIFactory4, then a IDXGIFactory2, then a IDXGIFactory1,
/// Tries to create a IDXGIFactory6, then a IDXGIFactory4, then a IDXGIFactory2, then a IDXGIFactory1,
/// returning the one that succeeds, or if the required_factory_type fails to be
/// created.
pub fn create_factory(
Expand Down Expand Up @@ -61,9 +185,9 @@ pub fn create_factory(
}

// Try to create IDXGIFactory4
match lib_dxgi.create_factory2(factory_flags) {
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
Ok(pair) => match pair.into_result() {
Ok(factory) => return Ok((lib_dxgi, DxgiFactory::Factory4(factory))),
Ok(factory) => Some(factory),
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
Err(err) => {
log::error!("Failed to create IDXGIFactory4: {}", err);
Expand All @@ -78,9 +202,33 @@ pub fn create_factory(
// If we don't print it to info as all win7 will hit this case.
Err(err) => {
log::info!("IDXGIFactory1 creation function not found: {:?}", err);
None
}
};

if let Some(factory4) = factory4 {
// Try to cast the IDXGIFactory4 into IDXGIFactory6
let factory6 = unsafe { factory4.cast::<dxgi1_6::IDXGIFactory6>().into_result() };
match factory6 {
Ok(factory6) => {
unsafe {
factory4.destroy();
}
return Ok((lib_dxgi, DxgiFactory::Factory6(factory6)));
}
// If we require factory6, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
return Err(crate::InstanceError);
}
// If we don't print it to info.
Err(err) => {
log::info!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
return Ok((lib_dxgi, DxgiFactory::Factory4(factory4)));
}
}
}

// Try to create IDXGIFactory1
let factory1 = match lib_dxgi.create_factory1() {
Ok(pair) => match pair.into_result() {
Expand All @@ -100,7 +248,12 @@ pub fn create_factory(
// Try to cast the IDXGIFactory1 into IDXGIFactory2
let factory2 = unsafe { factory1.cast::<dxgi1_2::IDXGIFactory2>().into_result() };
match factory2 {
Ok(factory2) => return Ok((lib_dxgi, DxgiFactory::Factory2(factory2))),
Ok(factory2) => {
unsafe {
factory1.destroy();
}
return Ok((lib_dxgi, DxgiFactory::Factory2(factory2)));
}
// If we require factory2, hard error.
Err(err) if required_factory_type == DxgiFactoryType::Factory2 => {
log::warn!("Failed to cast IDXGIFactory1 to IDXGIFactory2: {:?}", err);
Expand Down
6 changes: 1 addition & 5 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,7 @@ impl crate::Adapter<super::Api> for super::Adapter {

let mut present_modes = vec![wgt::PresentMode::Fifo];
#[allow(trivial_casts)]
if let Ok(factory5) = surface
.factory
.cast::<dxgi1_5::IDXGIFactory5>()
.into_result()
{
if let Some(factory5) = surface.factory.as_factory5() {
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
let hr = factory5.CheckFeatureSupport(
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
Expand Down
83 changes: 7 additions & 76 deletions wgpu-hal/src/dx12/instance.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
use super::SurfaceTarget;
use crate::auxil::{self, dxgi::result::HResult as _};
use std::sync::Arc;
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_6, winerror},
Interface,
};

impl Drop for super::Instance {
fn drop(&mut self) {
unsafe {
self.factory.destroy();
crate::auxil::dxgi::exception::unregister_exception_handler();
}
self.factory.destroy();
crate::auxil::dxgi::exception::unregister_exception_handler();
}
}

Expand Down Expand Up @@ -45,7 +39,7 @@ impl crate::Instance<super::Api> for super::Instance {

Ok(Self {
// The call to create_factory will only succeed if we get a factory4, so this is safe.
factory: factory.unwrap_factory4(),
factory,
library: Arc::new(lib_main),
_lib_dxgi: lib_dxgi,
flags: desc.flags,
Expand All @@ -70,74 +64,11 @@ impl crate::Instance<super::Api> for super::Instance {
}

unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
// Try to use high performance order by default (returns None on Windows < 1803)
let factory6 = match self.factory.cast::<dxgi1_6::IDXGIFactory6>().into_result() {
Ok(f6) => {
// It's okay to decrement the refcount here because we
// have another reference to the factory already owned by `self`.
f6.destroy();
Some(f6)
}
Err(err) => {
log::info!("Failed to cast DXGI to 1.6: {}", err);
None
}
};

// Enumerate adapters
let mut adapters = Vec::new();
for cur_index in 0.. {
let raw = match factory6 {
Some(factory) => {
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
let mut adapter2 = native::WeakPtr::<dxgi1_2::IDXGIAdapter2>::null();
let hr = factory.EnumAdapterByGpuPreference(
cur_index,
dxgi1_6::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&dxgi1_2::IDXGIAdapter2::uuidof(),
adapter2.mut_void(),
);

if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}

adapter2
}
None => {
profiling::scope!("IDXGIFactory1::EnumAdapters1");
let mut adapter1 = native::WeakPtr::<dxgi::IDXGIAdapter1>::null();
let hr = self
.factory
.EnumAdapters1(cur_index, adapter1.mut_void() as *mut *mut _);

if hr == winerror::DXGI_ERROR_NOT_FOUND {
break;
}
if let Err(err) = hr.into_result() {
log::error!("Failed enumerating adapters: {}", err);
break;
}
let adapters = self.factory.enumerate_adapters();

match adapter1.cast::<dxgi1_2::IDXGIAdapter2>().into_result() {
Ok(adapter2) => {
adapter1.destroy();
adapter2
}
Err(err) => {
log::error!("Failed casting to Adapter2: {}", err);
break;
}
}
}
};

adapters.extend(super::Adapter::expose(raw, &self.library, self.flags));
}
adapters
.into_iter()
.filter_map(|raw| super::Adapter::expose(raw, &self.library, self.flags))
.collect()
}
}
Loading

0 comments on commit 1ce3c63

Please sign in to comment.