diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 3f4648b25102db..ceb82c67492928 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -65,6 +65,9 @@ #include "common/RedtapeWindows.h" #include #include +#include +#include +#include #endif #ifdef __APPLE__ @@ -2237,6 +2240,151 @@ bool VMManager::IsLoadableFileName(const std::string_view& path) return IsDiscFileName(path) || IsElfFileName(path) || IsGSDumpFileName(path) || IsBlockDumpFileName(path); } +#ifdef _WIN32 +inline void LogUserPowerPlan() +{ + wil::unique_any pPwrGUID; + DWORD ret = PowerGetActiveScheme(NULL, pPwrGUID.put()); + if (ret != ERROR_SUCCESS) + return; + + UCHAR aBuffer[2048]; + DWORD aBufferSize = sizeof(aBuffer); + ret = PowerReadFriendlyName(NULL, pPwrGUID.get(), &NO_SUBGROUP_GUID, NULL, aBuffer, &aBufferSize); + std::string friendlyName(StringUtil::WideStringToUTF8String((wchar_t*)aBuffer)); + if (ret != ERROR_SUCCESS) + return; + + DWORD acMax = 0, acMin = 0, dcMax = 0, dcMin = 0; + + if (PowerReadACValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MAXIMUM, &acMax) || + PowerReadACValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MINIMUM, &acMin) || + PowerReadDCValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MAXIMUM, &dcMax) || + PowerReadDCValueIndex(NULL, pPwrGUID.get(), &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_THROTTLE_MINIMUM, &dcMin)) + return; + + Console.WriteLnFmt( + " Power Profile = '{}'\n" + " Power States (min/max)\n" + " AC = {}% / {}%\n" + " Battery = {}% / {}%\n", friendlyName.c_str(), acMin, acMax, dcMin, dcMax); +} +#endif + +#if defined(__linux__) || defined(_WIN32) +void LogGPUCapabilities() +{ + Console.WriteLn(Color_StrongBlack, "Graphics Adapters Detected:"); +#if defined(_WIN32) + IDXGIFactory1* pFactory = nullptr; + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) + return; + + UINT i = 0; + IDXGIAdapter* pAdapter = nullptr; + while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND) + { + DXGI_ADAPTER_DESC desc; + LARGE_INTEGER umdver; + if (SUCCEEDED(pAdapter->GetDesc(&desc)) && SUCCEEDED(pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &umdver))) + { + Console.WriteLnFmt( + " GPU = {}\n" + " Driver Version = {}.{}.{}.{}\n", + StringUtil::WideStringToUTF8String(desc.Description), + umdver.QuadPart >> 48, + (umdver.QuadPart >> 32) & 0xFFFF, + (umdver.QuadPart >> 16) & 0xFFFF, + umdver.QuadPart & 0xFFFF); + + i++; + pAdapter->Release(); + pAdapter = nullptr; + } + else + { + pAdapter->Release(); + pAdapter = nullptr; + + break; + } + } + + if (pAdapter) + pAdapter->Release(); + pFactory->Release(); +#else + // Credits to neofetch for the following (modified) script + std::string gpu_script = R"gpu_script( + lspci -mm | + awk -F '\"|\" \"|\\(' \ + '/"Display|"3D|"VGA/ { + a[$0] = $1 "" $3 " " ($(NF-1) ~ /^$|^Device [[:xdigit:]]+$/ ? $4 : $(NF-1)) + } + END { for (i in a) { + if (!seen[a[i]]++) { + sub("^[^ ]+ ", "", a[i]); + print a[i] + } + }}' + )gpu_script"; + + FILE* f = popen(gpu_script.c_str(), "r"); + if (f) + { + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), f)) + { + std::string card(buffer); + std::string version = "Unknown\n"; + if (card.find("NVIDIA") != std::string::npos) + { + // Assumes that all NVIDIA cards use the same driver + FILE* fnsmi = popen("nvidia-smi --query-gpu=driver_version --format=csv,noheader", "r"); + if (fnsmi) + { + if (fgets(buffer, sizeof(buffer), fnsmi)) + { + version = std::string(buffer); + } + pclose(fnsmi); + } + } + else + { + // Assuming non-NVIDIA cards are using the mesa driver + FILE* fglxinfo = popen("glxinfo | grep \"OpenGL version string\"", "r"); + if (fglxinfo) + { + if (fgets(buffer, sizeof(buffer), fglxinfo)) + { + version = std::string(buffer); + + // This path is taken if the card was Intel or AMD + // If glxinfo is reporting NVIDIA, then it's likely that this is a multi-gpu system + // and that this version doesn't apply to this AMD / Intel device + // Alternatively we could use vulkaninfo, which allows us to select the device + // But I was unable to get that to work on my system + // So for now, we cannot get the iGPU version on NVIDIA dGPU systems + if (version.find("NVIDIA") != std::string::npos) + { + version = "Unknown (OpenGL default is NVIDIA)\n"; + } + } + pclose(fglxinfo); + } + } + Console.WriteLnFmt( + " GPU = {}" + " Driver Version = {}", + card, version); + } + pclose(f); + } +#endif +} +#endif + void VMManager::LogCPUCapabilities() { Console.WriteLn(Color_StrongGreen, "PCSX2 " GIT_REV); @@ -2254,6 +2402,9 @@ void VMManager::LogCPUCapabilities() Console.WriteLnFmt(" Processor = {}", cpuinfo_get_package(0)->name); Console.WriteLnFmt(" Core Count = {} cores", cpuinfo_get_cores_count()); Console.WriteLnFmt(" Thread Count = {} threads", cpuinfo_get_processors_count()); +#ifdef _WIN32 + LogUserPowerPlan(); +#endif Console.WriteLn(); std::string features; @@ -2267,6 +2418,10 @@ void VMManager::LogCPUCapabilities() Console.WriteLn(Color_StrongBlack, "x86 Features Detected:"); Console.WriteLnFmt(" {}", features); Console.WriteLn(); + +#if defined(__linux__) || defined(_WIN32) + LogGPUCapabilities(); +#endif }