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" ," 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