Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions wgpu-core/src/pipeline_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ mod tests {
vendor: 0x0002_FEED,
device: 0xFEFE_FEFE,
device_type: wgt::DeviceType::Other,
device_pci_bus_id: String::new(),
driver: String::new(),
driver_info: String::new(),
backend: wgt::Backend::Vulkan,
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ dx12 = [
"dep:range-alloc",
"dep:windows-core",
"gpu-allocator/d3d12",
"windows/Win32_Devices_DeviceAndDriverInstallation",
"windows/Win32_Graphics_Direct3D_Fxc",
"windows/Win32_Graphics_Direct3D_Dxc",
"windows/Win32_Graphics_Direct3D",
Expand Down
151 changes: 151 additions & 0 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use parking_lot::Mutex;
use windows::{
core::Interface as _,
Win32::{
Devices::DeviceAndDriverInstallation::{
SetupDiDestroyDeviceInfoList, SetupDiEnumDeviceInfo, SetupDiGetClassDevsW,
SetupDiGetDeviceRegistryPropertyW, DIGCF_PRESENT, GUID_DEVCLASS_DISPLAY, HDEVINFO,
SPDRP_ADDRESS, SPDRP_BUSNUMBER, SPDRP_HARDWAREID, SP_DEVINFO_DATA,
},
Foundation::{GetLastError, ERROR_NO_MORE_ITEMS},
Graphics::{Direct3D, Direct3D12, Dxgi},
UI::WindowsAndMessaging,
},
Expand Down Expand Up @@ -127,6 +133,7 @@ impl super::Adapter {
} else {
wgt::DeviceType::DiscreteGpu
},
device_pci_bus_id: get_adapter_pci_info(desc.VendorId, desc.DeviceId),
driver: {
if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } {
const MASK: i64 = 0xFFFF;
Expand Down Expand Up @@ -1007,3 +1014,147 @@ impl crate::Adapter for super::Adapter {
wgt::PresentationTimestamp(self.presentation_timer.get_timestamp_ns())
}
}

fn get_adapter_pci_info(vendor_id: u32, device_id: u32) -> String {
// SAFETY: SetupDiGetClassDevsW is called with valid parameters
let device_info_set = unsafe {
match SetupDiGetClassDevsW(Some(&GUID_DEVCLASS_DISPLAY), None, None, DIGCF_PRESENT) {
Ok(set) => set,
Err(_) => return String::new(),
}
};

struct DeviceInfoSetGuard(HDEVINFO);
impl Drop for DeviceInfoSetGuard {
fn drop(&mut self) {
// SAFETY: device_info_set is a valid HDEVINFO and is only dropped once via this guard
unsafe {
let _ = SetupDiDestroyDeviceInfoList(self.0);
}
}
}
let _guard = DeviceInfoSetGuard(device_info_set);

let mut device_index = 0u32;
loop {
let mut device_info_data = SP_DEVINFO_DATA {
cbSize: size_of::<SP_DEVINFO_DATA>() as u32,
..Default::default()
};

// SAFETY: device_info_set is a valid HDEVINFO, device_index starts at 0 and
// device_info_data is properly initialized above
unsafe {
if SetupDiEnumDeviceInfo(device_info_set, device_index, &mut device_info_data).is_err()
{
if GetLastError() == ERROR_NO_MORE_ITEMS {
break;
}
device_index += 1;
continue;
}
}

let mut hardware_id_size = 0u32;
// SAFETY: device_info_set and device_info_data are valid
unsafe {
let _ = SetupDiGetDeviceRegistryPropertyW(
device_info_set,
&device_info_data,
SPDRP_HARDWAREID,
None,
None,
Some(&mut hardware_id_size),
);
}

if hardware_id_size == 0 {
device_index += 1;
continue;
}

let mut hardware_id_buffer = vec![0u8; hardware_id_size as usize];
// SAFETY: device_info_set and device_info_data are valid
unsafe {
if SetupDiGetDeviceRegistryPropertyW(
device_info_set,
&device_info_data,
SPDRP_HARDWAREID,
None,
Some(&mut hardware_id_buffer),
Some(&mut hardware_id_size),
)
.is_err()
{
device_index += 1;
continue;
}
}

let hardware_id_u16: Vec<u16> = hardware_id_buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.collect();
let hardware_ids: Vec<String> = hardware_id_u16
.split(|&c| c == 0)
.filter(|s| !s.is_empty())
.map(|s| String::from_utf16_lossy(s).to_uppercase())
.collect();

// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
let expected_id = format!("PCI\\VEN_{vendor_id:04X}&DEV_{device_id:04X}");
if !hardware_ids.iter().any(|id| id.contains(&expected_id)) {
device_index += 1;
continue;
}

let mut bus_buffer = [0u8; 4];
let mut data_size = bus_buffer.len() as u32;
// SAFETY: device_info_set and device_info_data are valid
let bus_number = unsafe {
if SetupDiGetDeviceRegistryPropertyW(
device_info_set,
&device_info_data,
SPDRP_BUSNUMBER,
None,
Some(&mut bus_buffer),
Some(&mut data_size),
)
.is_err()
{
device_index += 1;
continue;
}
u32::from_le_bytes(bus_buffer)
};

let mut addr_buffer = [0u8; 4];
let mut addr_size = addr_buffer.len() as u32;
// SAFETY: device_info_set and device_info_data are valid
unsafe {
if SetupDiGetDeviceRegistryPropertyW(
device_info_set,
&device_info_data,
SPDRP_ADDRESS,
None,
Some(&mut addr_buffer),
Some(&mut addr_size),
)
.is_err()
{
device_index += 1;
continue;
}
}
let address = u32::from_le_bytes(addr_buffer);

// https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/obtaining-device-configuration-information-at-irql---dispatch-level
let device = (address >> 16) & 0x0000FFFF;
let function = address & 0x0000FFFF;

// domain:bus:device.function
return format!("{:04x}:{:02x}:{:02x}.{:x}", 0, bus_number, device, function);
}

String::new()
}
1 change: 1 addition & 0 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ impl super::Adapter {
device: 0,
device_type: inferred_device_type,
driver: "".to_owned(),
device_pci_bus_id: String::new(),
driver_info: version,
backend: wgt::Backend::Gl,
}
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ impl crate::Instance for Instance {
vendor: 0,
device: 0,
device_type: shared.private_caps.device_type(),
device_pci_bus_id: String::new(),
driver: String::new(),
driver_info: String::new(),
backend: wgt::Backend::Metal,
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/noop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ pub fn adapter_info() -> wgt::AdapterInfo {
vendor: 0,
device: 0,
device_type: wgt::DeviceType::Cpu,
device_pci_bus_id: String::new(),
driver: String::from("wgpu"),
driver_info: String::new(),
backend: wgt::Backend::Noop,
Expand Down
23 changes: 23 additions & 0 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,10 @@ pub struct PhysicalDeviceProperties {
/// `VK_EXT_mesh_shader` extension.
mesh_shader: Option<vk::PhysicalDeviceMeshShaderPropertiesEXT<'static>>,

/// Additional `vk::PhysicalDevice` properties from the
/// `VK_EXT_pci_bus_info` extension.
pci_bus_info: Option<vk::PhysicalDevicePCIBusInfoPropertiesEXT<'static>>,

/// The device API version.
///
/// Which is the version of Vulkan supported for device-level functionality.
Expand Down Expand Up @@ -1392,6 +1396,8 @@ impl super::InstanceShared {
>= vk::API_VERSION_1_3
|| capabilities.supports_extension(ext::subgroup_size_control::NAME);
let supports_robustness2 = capabilities.supports_extension(ext::robustness2::NAME);
let supports_pci_bus_info =
capabilities.supports_extension(ext::pci_bus_info::NAME);

let supports_acceleration_structure =
capabilities.supports_extension(khr::acceleration_structure::NAME);
Expand Down Expand Up @@ -1448,6 +1454,13 @@ impl super::InstanceShared {
properties2 = properties2.push_next(next);
}

if supports_pci_bus_info {
let next = capabilities
.pci_bus_info
.insert(vk::PhysicalDevicePCIBusInfoPropertiesEXT::default());
properties2 = properties2.push_next(next);
}

if supports_mesh_shader {
let next = capabilities
.mesh_shader
Expand Down Expand Up @@ -1662,6 +1675,16 @@ impl super::Instance {
vk::PhysicalDeviceType::CPU => wgt::DeviceType::Cpu,
_ => wgt::DeviceType::Other,
},
device_pci_bus_id: phd_capabilities
.pci_bus_info
.filter(|info| info.pci_bus != 0 || info.pci_device != 0)
.map(|info| {
format!(
"{:04x}:{:02x}:{:02x}.{}",
info.pci_domain, info.pci_bus, info.pci_device, info.pci_function
)
})
.unwrap_or_default(),
driver: {
phd_capabilities
.driver
Expand Down
1 change: 1 addition & 0 deletions wgpu-info/src/human.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ fn print_adapter(output: &mut impl io::Write, report: &AdapterReport, idx: usize
writeln!(output, "\t Name: {}", info.name)?;
writeln!(output, "\t VendorID: {:#X?}", info.vendor)?;
writeln!(output, "\t DeviceID: {:#X?}", info.device)?;
writeln!(output, "\t DevicePCIBusId: {}", print_empty_string(&info.device_pci_bus_id))?;
writeln!(output, "\t Type: {:?}", info.device_type)?;
writeln!(output, "\t Driver: {}", print_empty_string(&info.driver))?;
writeln!(output, "\t DriverInfo: {}", print_empty_string(&info.driver_info))?;
Expand Down
7 changes: 7 additions & 0 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,13 @@ pub struct AdapterInfo {
pub device: u32,
/// Type of device
pub device_type: DeviceType,
/// [`Backend`]-specific PCI bus ID of the adapter.
///
/// * For [`Backend::Vulkan`], [`VkPhysicalDevicePCIBusInfoPropertiesEXT`] is used,
/// if available, in the form `bus:device.function`, e.g. `0000:01:00.0`.
///
/// [`VkPhysicalDevicePCIBusInfoPropertiesEXT`]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html
pub device_pci_bus_id: String,
/// Driver name
pub driver: String,
/// Driver info
Expand Down
1 change: 1 addition & 0 deletions wgpu/src/backend/webgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,7 @@ impl dispatch::AdapterInterface for WebAdapter {
vendor: 0,
device: 0,
device_type: wgt::DeviceType::Other,
device_pci_bus_id: String::new(),
driver: String::new(),
driver_info: String::new(),
backend: wgt::Backend::BrowserWebGpu,
Expand Down