Skip to content

Commit 4901538

Browse files
authored
from another agent
there might be stuff here from that is better
1 parent e96668f commit 4901538

1 file changed

Lines changed: 365 additions & 0 deletions

File tree

testcode/AdapterOption.h

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
#pragma once
2+
3+
#include <wrl/client.h> // For ComPtr
4+
#include <dxgi.h> // For IDXGIAdapter, IDXGIFactory1
5+
#include <algorithm> // For sort
6+
#include <setupapi.h>
7+
#include <devguid.h>
8+
#include <devpropdef.h>
9+
#include <devpkey.h>
10+
#include <cstdint>
11+
#include <optional>
12+
#include <string>
13+
#include <vector>
14+
#include <fstream>
15+
16+
using namespace std;
17+
using namespace Microsoft::WRL;
18+
19+
// DEVPKEY_Device_Luid: {60b193cb-5276-4d0f-96fc-f173ab17af69}, 2
20+
// Define it ourselves to avoid SDK/WDK header differences where DEVPKEY_Device_Luid may not be declared.
21+
static const DEVPROPKEY DEVPKEY_Device_Luid_Custom = {
22+
{ 0x60b193cb, 0x5276, 0x4d0f, { 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6 } },
23+
2
24+
};
25+
26+
// Structure to vector gpus
27+
struct GPUInfo {
28+
wstring name; // GPU name
29+
ComPtr<IDXGIAdapter> adapter;// COM pointer to the adapter
30+
DXGI_ADAPTER_DESC desc; // Adapter description
31+
};
32+
33+
// Sort function for GPUs by dedicated video memory
34+
bool CompareGPUs(const GPUInfo& a, const GPUInfo& b) {
35+
return a.desc.DedicatedVideoMemory > b.desc.DedicatedVideoMemory;
36+
}
37+
38+
// Get a enumerate list of available GPUs
39+
vector<GPUInfo> getAvailableGPUs() {
40+
vector<GPUInfo> gpus; // Vector to hold all GPU's information
41+
42+
ComPtr<IDXGIFactory1> factory;
43+
if (!SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) {
44+
return gpus;
45+
}
46+
47+
// Enumerate all adapters (GPUs)
48+
for (UINT i = 0;; i++) {
49+
ComPtr<IDXGIAdapter> adapter;
50+
if (!SUCCEEDED(factory->EnumAdapters(i, &adapter))) {
51+
break;
52+
}
53+
54+
DXGI_ADAPTER_DESC desc;
55+
56+
if (!SUCCEEDED(adapter->GetDesc(&desc))) {
57+
continue;
58+
}
59+
60+
// Add the adapter information to the list
61+
GPUInfo info{ desc.Description, adapter, desc };
62+
gpus.push_back(info);
63+
}
64+
65+
return gpus;
66+
}
67+
68+
// Find the integrated GPU (iGPU) from available adapters
69+
// Returns optional LUID if iGPU is found, nullopt otherwise
70+
inline std::optional<LUID> findiGPU() {
71+
auto gpus = getAvailableGPUs();
72+
if (gpus.empty()) {
73+
return std::nullopt;
74+
}
75+
76+
// iGPU detection criteria:
77+
// 1. Not a software adapter (has dedicated video memory > 0)
78+
// 2. Low dedicated video memory (typically < 512MB for integrated)
79+
// 3. Usually Intel HD/UHD graphics (Vendor ID 0x8086) or AMD APU (Vendor ID 0x1002)
80+
// 4. Often the GPU with least dedicated memory (excluding software adapters)
81+
82+
const UINT64 iGPUMemoryThreshold = 512ULL * 1024ULL * 1024ULL; // 512MB threshold
83+
const UINT intelVendorId = 0x8086; // Intel
84+
const UINT amdVendorId = 0x1002; // AMD (for APUs)
85+
86+
std::optional<LUID> iGPULuid = std::nullopt;
87+
UINT64 minDedicatedMemory = UINT64_MAX;
88+
const GPUInfo* candidateGPU = nullptr;
89+
90+
// First pass: Look for Intel or AMD integrated graphics with low memory
91+
for (const auto& gpu : gpus) {
92+
const auto& desc = gpu.desc;
93+
94+
// Skip software adapters (zero dedicated memory)
95+
if (desc.DedicatedVideoMemory == 0) {
96+
continue;
97+
}
98+
99+
// Check for integrated GPU characteristics
100+
bool isLikelyiGPU = false;
101+
102+
// Check by vendor ID (Intel or AMD APU)
103+
if (desc.VendorId == intelVendorId || desc.VendorId == amdVendorId) {
104+
// Intel HD/UHD graphics typically have specific naming patterns
105+
wstring name = desc.Description;
106+
if (name.find(L"Intel") != wstring::npos &&
107+
(name.find(L"HD") != wstring::npos || name.find(L"UHD") != wstring::npos)) {
108+
isLikelyiGPU = true;
109+
}
110+
// Check if it has low dedicated memory (typical for iGPU)
111+
if (desc.DedicatedVideoMemory < iGPUMemoryThreshold) {
112+
isLikelyiGPU = true;
113+
}
114+
}
115+
116+
// Track the GPU with least dedicated memory (usually iGPU)
117+
if (desc.DedicatedVideoMemory < minDedicatedMemory) {
118+
minDedicatedMemory = desc.DedicatedVideoMemory;
119+
// Prioritize Intel/AMD candidates, but also consider low memory GPUs
120+
if (isLikelyiGPU || desc.DedicatedVideoMemory < iGPUMemoryThreshold) {
121+
candidateGPU = &gpu;
122+
}
123+
}
124+
}
125+
126+
// If we found a candidate with Intel/AMD or low memory, return it
127+
if (candidateGPU != nullptr) {
128+
return candidateGPU->desc.AdapterLuid;
129+
}
130+
131+
// Fallback: If no clear iGPU found by vendor, return the GPU with least memory
132+
// (assuming discrete GPUs typically have more memory)
133+
if (minDedicatedMemory != UINT64_MAX && minDedicatedMemory < iGPUMemoryThreshold) {
134+
for (const auto& gpu : gpus) {
135+
if (gpu.desc.DedicatedVideoMemory == minDedicatedMemory) {
136+
return gpu.desc.AdapterLuid;
137+
}
138+
}
139+
}
140+
141+
return std::nullopt;
142+
}
143+
144+
// Get iGPU name if available
145+
inline wstring getiGPUName() {
146+
auto luidOpt = findiGPU();
147+
if (!luidOpt.has_value()) {
148+
return L"";
149+
}
150+
151+
auto gpus = getAvailableGPUs();
152+
for (const auto& gpu : gpus) {
153+
if (gpu.desc.AdapterLuid.LowPart == luidOpt.value().LowPart &&
154+
gpu.desc.AdapterLuid.HighPart == luidOpt.value().HighPart) {
155+
return gpu.name;
156+
}
157+
}
158+
159+
return L"";
160+
}
161+
162+
// Resolve an adapter LUID from a PCI bus number by enumerating display devices (SetupAPI).
163+
// Returns nullopt if no match is found or if the system doesn't expose the LUID property.
164+
inline std::optional<LUID> ResolveAdapterLuidFromPciBus(uint32_t targetBusIndex) {
165+
HDEVINFO devInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, nullptr, nullptr, DIGCF_PRESENT);
166+
if (devInfo == INVALID_HANDLE_VALUE) {
167+
return std::nullopt;
168+
}
169+
170+
SP_DEVINFO_DATA devData = {};
171+
devData.cbSize = sizeof(devData);
172+
173+
std::optional<LUID> result = std::nullopt;
174+
175+
for (DWORD i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devData); ++i) {
176+
DWORD currentBus = 0;
177+
if (!SetupDiGetDeviceRegistryPropertyW(
178+
devInfo,
179+
&devData,
180+
SPDRP_BUSNUMBER,
181+
nullptr,
182+
reinterpret_cast<PBYTE>(&currentBus),
183+
sizeof(currentBus),
184+
nullptr)) {
185+
continue;
186+
}
187+
188+
if (static_cast<uint32_t>(currentBus) != targetBusIndex) {
189+
continue;
190+
}
191+
192+
// DEVPKEY_Device_Luid is exposed as a UINT64 on Windows; convert into LUID.
193+
DEVPROPTYPE propType = 0;
194+
ULONG propSize = 0;
195+
ULONGLONG luid64 = 0;
196+
197+
if (!SetupDiGetDevicePropertyW(
198+
devInfo,
199+
&devData,
200+
&DEVPKEY_Device_Luid_Custom,
201+
&propType,
202+
reinterpret_cast<PBYTE>(&luid64),
203+
sizeof(luid64),
204+
&propSize,
205+
0)) {
206+
continue;
207+
}
208+
209+
if (propType != DEVPROP_TYPE_UINT64 || propSize != sizeof(luid64)) {
210+
continue;
211+
}
212+
213+
LUID luid{};
214+
luid.LowPart = static_cast<DWORD>(luid64 & 0xFFFFFFFFull);
215+
luid.HighPart = static_cast<LONG>((luid64 >> 32) & 0xFFFFFFFFull);
216+
result = luid;
217+
break;
218+
}
219+
220+
SetupDiDestroyDeviceInfoList(devInfo);
221+
return result;
222+
}
223+
224+
class AdapterOption {
225+
public:
226+
bool hasTargetAdapter{}; // Indicates if a target adapter is selected
227+
LUID adapterLuid{}; // Adapter's unique identifier (LUID)
228+
wstring target_name{}; // Target adapter name
229+
230+
// --- iGPU SUPPORT ---
231+
bool hasiGPU{}; // Indicates if an iGPU was detected
232+
LUID iGPULuid{}; // Integrated GPU's unique identifier (LUID)
233+
wstring iGPU_name{}; // Integrated GPU name
234+
// --- END iGPU SUPPORT ---
235+
236+
// Select the best GPU based on dedicated video memory
237+
wstring selectBestGPU() {
238+
auto gpus = getAvailableGPUs();
239+
if (gpus.empty()) {
240+
return L""; // Error check for headless / vm
241+
}
242+
243+
// Sort GPUs by dedicated video memory in descending order
244+
sort(gpus.begin(), gpus.end(), CompareGPUs);
245+
auto bestGPU = gpus.front(); // Get the GPU with the most memory
246+
247+
return bestGPU.name;
248+
}
249+
250+
// Load friendlyname from a file OR select the best GPU
251+
void load(const wchar_t* path) {
252+
ifstream ifs{ path };
253+
254+
if (!ifs.is_open()) {
255+
target_name = selectBestGPU();
256+
}
257+
else {
258+
string line;
259+
getline(ifs, line);
260+
target_name.assign(line.begin(), line.end());
261+
}
262+
263+
// Find and set the adapter based on the target name
264+
if (!findAndSetAdapter(target_name)) {
265+
// If the adapter is not found, select the best GPU and retry
266+
target_name = selectBestGPU();
267+
findAndSetAdapter(target_name);
268+
}
269+
}
270+
271+
// Set the target adapter from a given name and validate it
272+
void xmlprovide(const wstring& xtarg) {
273+
target_name = xtarg;
274+
if (!findAndSetAdapter(target_name)) {
275+
// If the adapter is not found, select the best GPU and retry
276+
target_name = selectBestGPU();
277+
findAndSetAdapter(target_name);
278+
}
279+
}
280+
281+
// Apply the adapter settings to the specified adapter
282+
void apply(const IDDCX_ADAPTER& adapter) {
283+
if (hasTargetAdapter && IDD_IS_FUNCTION_AVAILABLE(IddCxAdapterSetRenderAdapter)) {
284+
IDARG_IN_ADAPTERSETRENDERADAPTER arg{};
285+
arg.PreferredRenderAdapter = adapterLuid;
286+
IddCxAdapterSetRenderAdapter(adapter, &arg);
287+
}
288+
}
289+
290+
// --- iGPU DETECTION METHODS ---
291+
// Detect and select the integrated GPU (iGPU)
292+
// Returns true if iGPU is found and set, false otherwise
293+
bool selectiGPU() {
294+
auto luidOpt = findiGPU();
295+
if (luidOpt.has_value()) {
296+
iGPULuid = luidOpt.value();
297+
iGPU_name = getiGPUName();
298+
hasiGPU = true;
299+
return true;
300+
}
301+
hasiGPU = false;
302+
return false;
303+
}
304+
305+
// Get the iGPU LUID if available
306+
std::optional<LUID> getiGPULuid() const {
307+
if (hasiGPU) {
308+
return iGPULuid;
309+
}
310+
return std::nullopt;
311+
}
312+
313+
// Check if iGPU is available
314+
bool hasIntegratedGPU() const {
315+
return hasiGPU;
316+
}
317+
318+
// Get iGPU name
319+
wstring getiGPUName() const {
320+
return iGPU_name;
321+
}
322+
// --- END iGPU DETECTION METHODS ---
323+
324+
private:
325+
// Find and set the adapter by name, optionally using "name,bus" where bus is the PCI bus number.
326+
bool findAndSetAdapter(const wstring& adapterSpec) {
327+
// If user provides "name,bus", use bus to resolve LUID (more deterministic on multi-GPU setups).
328+
const size_t comma = adapterSpec.find(L',');
329+
if (comma != wstring::npos) {
330+
const wstring namePart = adapterSpec.substr(0, comma);
331+
wstring busPart = adapterSpec.substr(comma + 1);
332+
// Trim whitespace in bus part
333+
busPart.erase(remove_if(busPart.begin(), busPart.end(), iswspace), busPart.end());
334+
335+
wchar_t* end = nullptr;
336+
const unsigned long busUl = wcstoul(busPart.c_str(), &end, 10);
337+
const bool parsedOk = (end != nullptr) && (*end == L'\0') && (end != busPart.c_str());
338+
if (parsedOk && busUl <= 0xFFFFFFFFul) {
339+
if (auto luidOpt = ResolveAdapterLuidFromPciBus(static_cast<uint32_t>(busUl)); luidOpt.has_value()) {
340+
adapterLuid = luidOpt.value();
341+
hasTargetAdapter = true;
342+
return true;
343+
}
344+
}
345+
346+
// Fall through to name matching using the name portion.
347+
return findAndSetAdapter(namePart);
348+
}
349+
350+
const wstring& adapterName = adapterSpec;
351+
auto gpus = getAvailableGPUs();
352+
353+
// Iterate through all available GPUs
354+
for (const auto& gpu : gpus) {
355+
if (_wcsicmp(gpu.name.c_str(), adapterName.c_str()) == 0) {
356+
adapterLuid = gpu.desc.AdapterLuid; // Set the adapter LUID
357+
hasTargetAdapter = true; // Indicate that a target adapter is selected
358+
return true;
359+
}
360+
}
361+
362+
hasTargetAdapter = false; // Indicate that no target adapter is selected
363+
return false;
364+
}
365+
};

0 commit comments

Comments
 (0)