Skip to content

Commit 05ae18d

Browse files
Merge pull request #413 from zjoasan/zjoasan-adapteroption-patch1
DeviceID, pcislot friendly name
2 parents 06b2dbd + 2a18a0b commit 05ae18d

File tree

1 file changed

+152
-24
lines changed

1 file changed

+152
-24
lines changed

Common/Include/AdapterOption.h

Lines changed: 152 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,109 @@
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

713
using namespace std;
814
using namespace Microsoft::WRL;
915

10-
// Structure to vector gpus
16+
// Structure to hold GPU information
1117
struct 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
1826
bool 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
2396
vector<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 {
53138
public:
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

112207
private:
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

Comments
 (0)