Skip to content
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
2 changes: 2 additions & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ dx12 = [
"dep:range-alloc",
"dep:windows-core",
"dep:gpu-allocator",
"gpu-allocator/d3d12",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kpreid is this a problem for feature sets? I'm never quite sure how implicit features work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh hmm, i may have resolved a merge conflict incorrectly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it — this line should be dropped. It would not hurt but it would not have any effect.

Copy link
Collaborator

@kpreid kpreid Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm never quite sure how implicit features work.

The rule is that if

  • a dependency is optional, and
  • not mentioned using dep: syntax anywhere in [features],

then it gets an implicit feature. (When RFC 3491 is implemented in a future edition, implicit features will no longer be created and this will be an error.)

"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 @@ -1023,3 +1030,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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How the hell did you figure out how to do this lmao

// 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
Loading