11#pragma once
22
3- #include < wrl/client.h> // For ComPtr
4- #include < dxgi.h> // For IDXGIAdapter, IDXGIFactory1
5- #include < algorithm> // For sort
3+ #include < wrl/client.h> // For ComPtr
4+ #include < dxgi.h> // For IDXGIAdapter, IDXGIFactory1
5+ #include < algorithm> // For sort
6+ #include < d3dkmt.h> // For D3DKMT functions
7+ #include < setupapi.h> // For SetupAPI
8+ #include < devpkey.h> // For DEVPKEY
9+ #include < cfgmgr32.h> // For CM_ functions
10+ #include < fstream> // For file I/O
11+ #include < string>
612
713using namespace std ;
814using namespace Microsoft ::WRL;
915
10- // Structure to vector gpus
16+ // Structure to hold GPU information
1117struct GPUInfo {
12- wstring name; // GPU name
18+ wstring name; // GPU friendly name (from DXGI_ADAPTER_DESC)
1319 ComPtr<IDXGIAdapter> adapter;// COM pointer to the adapter
1420 DXGI_ADAPTER_DESC desc; // Adapter description
21+ wstring deviceId; // Device Instance ID
22+ wstring slotInfo; // PCI slot information (e.g., "PCI Slot 2")
1523};
1624
1725// Sort function for GPUs by dedicated video memory
1826bool CompareGPUs (const GPUInfo& a, const GPUInfo& b) {
1927 return a.desc .DedicatedVideoMemory > b.desc .DedicatedVideoMemory ;
2028}
2129
22- // Get a enumerate list of available GPUs
30+ // Helper function to get Device Instance ID and PCI slot info from LUID
31+ struct AdapterDeviceInfo {
32+ wstring deviceId;
33+ wstring slotInfo;
34+ LUID luid;
35+ };
36+
37+ vector<AdapterDeviceInfo> GetAdapterDeviceInfos () {
38+ vector<AdapterDeviceInfo> adapterInfos;
39+
40+ // Enumerate display adapter interfaces
41+ HDEVINFO devInfo = SetupDiGetClassDevsW (&GUID_DEVINTERFACE_DISPLAY_ADAPTER, nullptr , nullptr , DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
42+ if (devInfo == INVALID_HANDLE_VALUE) {
43+ return adapterInfos;
44+ }
45+
46+ SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof (SP_DEVICE_INTERFACE_DATA) };
47+ for (DWORD i = 0 ; SetupDiEnumDeviceInterfaces (devInfo, nullptr , &GUID_DEVINTERFACE_DISPLAY_ADAPTER, i, &interfaceData); ++i) {
48+ // Get device interface path
49+ DWORD requiredSize = 0 ;
50+ SetupDiGetDeviceInterfaceDetailW (devInfo, &interfaceData, nullptr , 0 , &requiredSize, nullptr );
51+ vector<WCHAR> buffer (requiredSize / sizeof (WCHAR));
52+ PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail = reinterpret_cast <PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buffer.data ());
53+ detail->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA_W);
54+ if (!SetupDiGetDeviceInterfaceDetailW (devInfo, &interfaceData, detail, requiredSize, nullptr , nullptr )) {
55+ continue ;
56+ }
57+
58+ // Get LUID
59+ D3DKMT_OPENADAPTERFROMDEVICENAME openAdapter = {};
60+ openAdapter.pDeviceName = detail->DevicePath ;
61+ NTSTATUS status = D3DKMTOpenAdapterFromDeviceName (&openAdapter);
62+ if (!NT_SUCCESS (status)) {
63+ continue ;
64+ }
65+
66+ // Get Device Instance ID
67+ ULONG propSize = 0 ;
68+ DEVPROPTYPE propType;
69+ CM_Get_Device_Interface_PropertyW (detail->DevicePath , &DEVPKEY_Device_InstanceId, &propType, nullptr , &propSize, 0 );
70+ vector<BYTE> propBuffer (propSize);
71+ wstring deviceId;
72+ if (CM_Get_Device_Interface_PropertyW (detail->DevicePath , &DEVPKEY_Device_InstanceId, &propType, propBuffer.data (), &propSize, 0 ) == CR_SUCCESS) {
73+ deviceId = reinterpret_cast <PWCHAR>(propBuffer.data ());
74+ }
75+
76+ // Get PCI slot info
77+ propSize = 0 ;
78+ CM_Get_Device_Interface_PropertyW (detail->DevicePath , &DEVPKEY_Device_LocationInfo, &propType, nullptr , &propSize, 0 );
79+ propBuffer.resize (propSize);
80+ wstring slotInfo;
81+ if (CM_Get_Device_Interface_PropertyW (detail->DevicePath , &DEVPKEY_Device_LocationInfo, &propType, propBuffer.data (), &propSize, 0 ) == CR_SUCCESS) {
82+ slotInfo = reinterpret_cast <PWCHAR>(propBuffer.data ());
83+ }
84+
85+ adapterInfos.push_back ({ deviceId, slotInfo, openAdapter.AdapterLuid });
86+
87+ D3DKMT_CLOSEADAPTER closeAdapter = { openAdapter.hAdapter };
88+ D3DKMTCloseAdapter (&closeAdapter);
89+ }
90+
91+ SetupDiDestroyDeviceInfoList (devInfo);
92+ return adapterInfos;
93+ }
94+
95+ // Get a list of available GPUs with Device Instance ID and PCI slot info
2396vector<GPUInfo> getAvailableGPUs () {
24- vector<GPUInfo> gpus; // Vector to hold all GPU's information
97+ vector<GPUInfo> gpus;
2598
2699 ComPtr<IDXGIFactory1> factory;
27100 if (!SUCCEEDED (CreateDXGIFactory1 (IID_PPV_ARGS (&factory)))) {
28101 return gpus;
29102 }
30103
104+ // Get Device Instance IDs and slot info
105+ auto deviceInfos = GetAdapterDeviceInfos ();
106+
31107 // Enumerate all adapters (GPUs)
32108 for (UINT i = 0 ;; i++) {
33109 ComPtr<IDXGIAdapter> adapter;
@@ -36,13 +112,22 @@ vector<GPUInfo> getAvailableGPUs() {
36112 }
37113
38114 DXGI_ADAPTER_DESC desc;
39-
40115 if (!SUCCEEDED (adapter->GetDesc (&desc))) {
41116 continue ;
42117 }
43118
119+ // Find matching Device Instance ID and slot info
120+ wstring deviceId, slotInfo;
121+ for (const auto & deviceInfo : deviceInfos) {
122+ if (RtlEqualLuid (&desc.AdapterLuid , &deviceInfo.luid )) {
123+ deviceId = deviceInfo.deviceId ;
124+ slotInfo = deviceInfo.slotInfo ;
125+ break ;
126+ }
127+ }
128+
44129 // Add the adapter information to the list
45- GPUInfo info{ desc.Description , adapter, desc };
130+ GPUInfo info{ desc.Description , adapter, desc, deviceId, slotInfo };
46131 gpus.push_back (info);
47132 }
48133
@@ -53,26 +138,36 @@ class AdapterOption {
53138public:
54139 bool hasTargetAdapter{}; // Indicates if a target adapter is selected
55140 LUID adapterLuid{}; // Adapter's unique identifier (LUID)
56- wstring target_name{}; // Target adapter name
141+ wstring target_name{}; // Target adapter name (friendlyname,slot)
142+ wstring target_device_id{}; // Device Instance ID of selected adapter
57143
58144 // Select the best GPU based on dedicated video memory
59145 wstring selectBestGPU () {
60146 auto gpus = getAvailableGPUs ();
61147 if (gpus.empty ()) {
62- return L" " ; // Error check for headless / vm
148+ return L" " ; // Error check for headless/VM
63149 }
64150
65151 // Sort GPUs by dedicated video memory in descending order
66152 sort (gpus.begin (), gpus.end (), CompareGPUs);
67153 auto bestGPU = gpus.front (); // Get the GPU with the most memory
68154
69- return bestGPU.name ;
155+ // Return friendlyname,slot format
156+ return bestGPU.name + (bestGPU.slotInfo .empty () ? L" " : L" ," + bestGPU.slotInfo );
70157 }
71158
72- // Load friendlyname from a file OR select the best GPU
159+ // Parse friendlyname,pcislot input
160+ pair<wstring, wstring> parseTarget (const wstring& input) {
161+ auto pos = input.find (L' ,' );
162+ if (pos == wstring::npos) {
163+ return { input, L" " }; // No slot specified
164+ }
165+ return { input.substr (0 , pos), input.substr (pos + 1 ) }; // Friendly name, slot
166+ }
167+
168+ // Load friendlyname,slot from a file or select the best GPU
73169 void load (const wchar_t * path) {
74170 ifstream ifs{ path };
75-
76171 if (!ifs.is_open ()) {
77172 target_name = selectBestGPU ();
78173 }
@@ -82,15 +177,15 @@ class AdapterOption {
82177 target_name.assign (line.begin (), line.end ());
83178 }
84179
85- // Find and set the adapter based on the target name
180+ // Find and set the adapter based on the target name and slot
86181 if (!findAndSetAdapter (target_name)) {
87182 // If the adapter is not found, select the best GPU and retry
88183 target_name = selectBestGPU ();
89184 findAndSetAdapter (target_name);
90185 }
91186 }
92187
93- // Set the target adapter from a given name and validate it
188+ // Set the target adapter from a given name and slot (e.g., "NVIDIA GeForce RTX 3080,PCI Slot 2")
94189 void xmlprovide (const wstring& xtarg) {
95190 target_name = xtarg;
96191 if (!findAndSetAdapter (target_name)) {
@@ -110,20 +205,53 @@ class AdapterOption {
110205 }
111206
112207private:
113- // Find and set the adapter by its name
114- bool findAndSetAdapter (const wstring& adapterName ) {
208+ // Find and set the adapter by its friendly name and optional PCI slot
209+ bool findAndSetAdapter (const wstring& target ) {
115210 auto gpus = getAvailableGPUs ();
211+ if (gpus.empty ()) {
212+ hasTargetAdapter = false ;
213+ return false ;
214+ }
215+
216+ auto [targetName, targetSlot] = parseTarget (target);
116217
117- // Iterate through all available GPUs
218+ // Find all adapters matching the friendly name
219+ vector<GPUInfo> matchingGPUs;
118220 for (const auto & gpu : gpus) {
119- if (_wcsicmp (gpu.name .c_str (), adapterName.c_str ()) == 0 ) {
120- adapterLuid = gpu.desc .AdapterLuid ; // Set the adapter LUID
121- hasTargetAdapter = true ; // Indicate that a target adapter is selected
221+ if (_wcsicmp (gpu.name .c_str (), targetName.c_str ()) == 0 ) {
222+ matchingGPUs.push_back (gpu);
223+ }
224+ }
225+
226+ if (matchingGPUs.empty ()) {
227+ hasTargetAdapter = false ;
228+ return false ;
229+ }
230+
231+ // If only one match or no slot specified, use the first match
232+ if (matchingGPUs.size () == 1 || targetSlot.empty ()) {
233+ const auto & gpu = matchingGPUs.front ();
234+ adapterLuid = gpu.desc .AdapterLuid ;
235+ target_device_id = gpu.deviceId ;
236+ hasTargetAdapter = true ;
237+ return true ;
238+ }
239+
240+ // Multiple matches: use PCI slot to disambiguate
241+ for (const auto & gpu : matchingGPUs) {
242+ if (_wcsicmp (gpu.slotInfo .c_str (), targetSlot.c_str ()) == 0 ) {
243+ adapterLuid = gpu.desc .AdapterLuid ;
244+ target_device_id = gpu.deviceId ;
245+ hasTargetAdapter = true ;
122246 return true ;
123247 }
124248 }
125249
126- hasTargetAdapter = false ; // Indicate that no target adapter is selected
127- return false ;
250+ // No slot match found; fall back to first matching GPU
251+ const auto & gpu = matchingGPUs.front ();
252+ adapterLuid = gpu.desc .AdapterLuid ;
253+ target_device_id = gpu.deviceId ;
254+ hasTargetAdapter = true ;
255+ return true ;
128256 }
129257};
0 commit comments