@@ -6,6 +6,12 @@ use parking_lot::Mutex;
66use windows:: {
77 core:: Interface as _,
88 Win32 :: {
9+ Devices :: DeviceAndDriverInstallation :: {
10+ SetupDiDestroyDeviceInfoList , SetupDiEnumDeviceInfo , SetupDiGetClassDevsW ,
11+ SetupDiGetDeviceRegistryPropertyW , DIGCF_PRESENT , GUID_DEVCLASS_DISPLAY , HDEVINFO ,
12+ SPDRP_ADDRESS , SPDRP_BUSNUMBER , SPDRP_HARDWAREID , SP_DEVINFO_DATA ,
13+ } ,
14+ Foundation :: { GetLastError , ERROR_NO_MORE_ITEMS } ,
915 Graphics :: { Direct3D , Direct3D12 , Dxgi } ,
1016 UI :: WindowsAndMessaging ,
1117 } ,
@@ -127,6 +133,7 @@ impl super::Adapter {
127133 } else {
128134 wgt:: DeviceType :: DiscreteGpu
129135 } ,
136+ device_pci_bus_id : get_adapter_pci_info ( desc. VendorId , desc. DeviceId ) ,
130137 driver : {
131138 if let Ok ( i) = unsafe { adapter. CheckInterfaceSupport ( & Dxgi :: IDXGIDevice :: IID ) } {
132139 const MASK : i64 = 0xFFFF ;
@@ -1024,3 +1031,147 @@ impl crate::Adapter for super::Adapter {
10241031 wgt:: PresentationTimestamp ( self . presentation_timer . get_timestamp_ns ( ) )
10251032 }
10261033}
1034+
1035+ fn get_adapter_pci_info ( vendor_id : u32 , device_id : u32 ) -> String {
1036+ // SAFETY: SetupDiGetClassDevsW is called with valid parameters
1037+ let device_info_set = unsafe {
1038+ match SetupDiGetClassDevsW ( Some ( & GUID_DEVCLASS_DISPLAY ) , None , None , DIGCF_PRESENT ) {
1039+ Ok ( set) => set,
1040+ Err ( _) => return String :: new ( ) ,
1041+ }
1042+ } ;
1043+
1044+ struct DeviceInfoSetGuard ( HDEVINFO ) ;
1045+ impl Drop for DeviceInfoSetGuard {
1046+ fn drop ( & mut self ) {
1047+ // SAFETY: device_info_set is a valid HDEVINFO and is only dropped once via this guard
1048+ unsafe {
1049+ let _ = SetupDiDestroyDeviceInfoList ( self . 0 ) ;
1050+ }
1051+ }
1052+ }
1053+ let _guard = DeviceInfoSetGuard ( device_info_set) ;
1054+
1055+ let mut device_index = 0u32 ;
1056+ loop {
1057+ let mut device_info_data = SP_DEVINFO_DATA {
1058+ cbSize : size_of :: < SP_DEVINFO_DATA > ( ) as u32 ,
1059+ ..Default :: default ( )
1060+ } ;
1061+
1062+ // SAFETY: device_info_set is a valid HDEVINFO, device_index starts at 0 and
1063+ // device_info_data is properly initialized above
1064+ unsafe {
1065+ if SetupDiEnumDeviceInfo ( device_info_set, device_index, & mut device_info_data) . is_err ( )
1066+ {
1067+ if GetLastError ( ) == ERROR_NO_MORE_ITEMS {
1068+ break ;
1069+ }
1070+ device_index += 1 ;
1071+ continue ;
1072+ }
1073+ }
1074+
1075+ let mut hardware_id_size = 0u32 ;
1076+ // SAFETY: device_info_set and device_info_data are valid
1077+ unsafe {
1078+ let _ = SetupDiGetDeviceRegistryPropertyW (
1079+ device_info_set,
1080+ & device_info_data,
1081+ SPDRP_HARDWAREID ,
1082+ None ,
1083+ None ,
1084+ Some ( & mut hardware_id_size) ,
1085+ ) ;
1086+ }
1087+
1088+ if hardware_id_size == 0 {
1089+ device_index += 1 ;
1090+ continue ;
1091+ }
1092+
1093+ let mut hardware_id_buffer = vec ! [ 0u8 ; hardware_id_size as usize ] ;
1094+ // SAFETY: device_info_set and device_info_data are valid
1095+ unsafe {
1096+ if SetupDiGetDeviceRegistryPropertyW (
1097+ device_info_set,
1098+ & device_info_data,
1099+ SPDRP_HARDWAREID ,
1100+ None ,
1101+ Some ( & mut hardware_id_buffer) ,
1102+ Some ( & mut hardware_id_size) ,
1103+ )
1104+ . is_err ( )
1105+ {
1106+ device_index += 1 ;
1107+ continue ;
1108+ }
1109+ }
1110+
1111+ let hardware_id_u16: Vec < u16 > = hardware_id_buffer
1112+ . chunks_exact ( 2 )
1113+ . map ( |chunk| u16:: from_le_bytes ( [ chunk[ 0 ] , chunk[ 1 ] ] ) )
1114+ . collect ( ) ;
1115+ let hardware_ids: Vec < String > = hardware_id_u16
1116+ . split ( |& c| c == 0 )
1117+ . filter ( |s| !s. is_empty ( ) )
1118+ . map ( |s| String :: from_utf16_lossy ( s) . to_uppercase ( ) )
1119+ . collect ( ) ;
1120+
1121+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
1122+ let expected_id = format ! ( "PCI\\ VEN_{vendor_id:04X}&DEV_{device_id:04X}" ) ;
1123+ if !hardware_ids. iter ( ) . any ( |id| id. contains ( & expected_id) ) {
1124+ device_index += 1 ;
1125+ continue ;
1126+ }
1127+
1128+ let mut bus_buffer = [ 0u8 ; 4 ] ;
1129+ let mut data_size = bus_buffer. len ( ) as u32 ;
1130+ // SAFETY: device_info_set and device_info_data are valid
1131+ let bus_number = unsafe {
1132+ if SetupDiGetDeviceRegistryPropertyW (
1133+ device_info_set,
1134+ & device_info_data,
1135+ SPDRP_BUSNUMBER ,
1136+ None ,
1137+ Some ( & mut bus_buffer) ,
1138+ Some ( & mut data_size) ,
1139+ )
1140+ . is_err ( )
1141+ {
1142+ device_index += 1 ;
1143+ continue ;
1144+ }
1145+ u32:: from_le_bytes ( bus_buffer)
1146+ } ;
1147+
1148+ let mut addr_buffer = [ 0u8 ; 4 ] ;
1149+ let mut addr_size = addr_buffer. len ( ) as u32 ;
1150+ // SAFETY: device_info_set and device_info_data are valid
1151+ unsafe {
1152+ if SetupDiGetDeviceRegistryPropertyW (
1153+ device_info_set,
1154+ & device_info_data,
1155+ SPDRP_ADDRESS ,
1156+ None ,
1157+ Some ( & mut addr_buffer) ,
1158+ Some ( & mut addr_size) ,
1159+ )
1160+ . is_err ( )
1161+ {
1162+ device_index += 1 ;
1163+ continue ;
1164+ }
1165+ }
1166+ let address = u32:: from_le_bytes ( addr_buffer) ;
1167+
1168+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/obtaining-device-configuration-information-at-irql---dispatch-level
1169+ let device = ( address >> 16 ) & 0x0000FFFF ;
1170+ let function = address & 0x0000FFFF ;
1171+
1172+ // domain:bus:device.function
1173+ return format ! ( "{:04x}:{:02x}:{:02x}.{:x}" , 0 , bus_number, device, function) ;
1174+ }
1175+
1176+ String :: new ( )
1177+ }
0 commit comments