diff options
Diffstat (limited to 'archived/projt-launcher/launcher/HardwareInfo.cpp')
| -rw-r--r-- | archived/projt-launcher/launcher/HardwareInfo.cpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/HardwareInfo.cpp b/archived/projt-launcher/launcher/HardwareInfo.cpp new file mode 100644 index 0000000000..90fd9c4aad --- /dev/null +++ b/archived/projt-launcher/launcher/HardwareInfo.cpp @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "HardwareInfo.h" + +#include <array> +#include <cstdio> + +#include <QDebug> +#include <QCoreApplication> +#include <QOffscreenSurface> +#include <QOpenGLFunctions> +#include <QVersionNumber> + +#if !defined(Q_OS_MACOS) && __has_include(<vulkan/vulkan.h>) && __has_include(<QVulkanInstance>) && __has_include(<QVulkanWindow>) +#define PROJT_HAS_VULKAN_INFO 1 +#include <vulkan/vulkan.h> +#include <QVulkanInstance> +#include <QVulkanWindow> +#endif + +namespace { +bool vulkanInfo(QStringList& out) +{ +#ifdef PROJT_HAS_VULKAN_INFO + QVulkanInstance inst; + if (!inst.create()) { + qWarning() << "Vulkan instance creation failed, VkResult:" << inst.errorCode(); + out << "Couldn't get Vulkan device information"; + return false; + } + + QVulkanWindow window; + window.setVulkanInstance(&inst); + + for (auto device : window.availablePhysicalDevices()) { + const auto supportedVulkanVersion = QVersionNumber(VK_API_VERSION_MAJOR(device.apiVersion), VK_API_VERSION_MINOR(device.apiVersion), + VK_API_VERSION_PATCH(device.apiVersion)); + out << QString("Found Vulkan device: %1 (API version %2)").arg(device.deviceName).arg(supportedVulkanVersion.toString()); + } +#else + out << "Vulkan device information unavailable at build time"; + return false; +#endif + + return true; +} + +bool openGlInfo(QStringList& out) +{ + QOpenGLContext ctx; + if (!ctx.create()) { + qWarning() << "OpenGL context creation failed"; + out << "Couldn't get OpenGL device information"; + return false; + } + + QOffscreenSurface surface; + surface.create(); + ctx.makeCurrent(&surface); + + auto* f = ctx.functions(); + f->initializeOpenGLFunctions(); + + auto toQString = [](const GLubyte* str) { return QString(reinterpret_cast<const char*>(str)); }; + out << "OpenGL driver vendor: " + toQString(f->glGetString(GL_VENDOR)); + out << "OpenGL renderer: " + toQString(f->glGetString(GL_RENDERER)); + out << "OpenGL driver version: " + toQString(f->glGetString(GL_VERSION)); + + return true; +} +} // namespace + +#ifndef Q_OS_LINUX +QStringList HardwareInfo::gpuInfo() +{ + QStringList info; + vulkanInfo(info); + openGlInfo(info); + return info; +} +#endif + +#ifdef Q_OS_WINDOWS +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <QSettings> + +#include "windows.h" + +QString HardwareInfo::cpuInfo() +{ + const QSettings registry(R"(HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0)", QSettings::NativeFormat); + return registry.value("ProcessorNameString").toString(); +} + +uint64_t HardwareInfo::totalRamMiB() +{ + MEMORYSTATUSEX status; + status.dwLength = sizeof status; + + if (GlobalMemoryStatusEx(&status) == TRUE) { + // transforming bytes -> mib + return status.ullTotalPhys / 1024 / 1024; + } + + qWarning() << "Could not get total RAM: GlobalMemoryStatusEx"; + return 0; +} + +uint64_t HardwareInfo::availableRamMiB() +{ + MEMORYSTATUSEX status; + status.dwLength = sizeof status; + + if (GlobalMemoryStatusEx(&status) == TRUE) { + // transforming bytes -> mib + return status.ullAvailPhys / 1024 / 1024; + } + + qWarning() << "Could not get available RAM: GlobalMemoryStatusEx"; + return 0; +} + +#elif defined(Q_OS_MACOS) +#include "mach/mach.h" +#include "sys/sysctl.h" + +QString HardwareInfo::cpuInfo() +{ + std::array<char, 512> buffer; + size_t bufferSize = buffer.size(); + if (sysctlbyname("machdep.cpu.brand_string", &buffer, &bufferSize, nullptr, 0) == 0) { + return QString(buffer.data()); + } + + qWarning() << "Could not get CPU model: sysctlbyname"; + return ""; +} + +uint64_t HardwareInfo::totalRamMiB() +{ + uint64_t memsize; + size_t memsizeSize = sizeof memsize; + if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, nullptr, 0) == 0) { + // transforming bytes -> mib + return memsize / 1024 / 1024; + } + + qWarning() << "Could not get total RAM: sysctlbyname"; + return 0; +} + +uint64_t HardwareInfo::availableRamMiB() +{ + mach_port_t host_port = mach_host_self(); + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + + vm_statistics64_data_t vm_stats; + + if (host_statistics64(host_port, HOST_VM_INFO64, reinterpret_cast<host_info64_t>(&vm_stats), &count) == KERN_SUCCESS) { + // transforming bytes -> mib + return (vm_stats.free_count + vm_stats.inactive_count) * vm_page_size / 1024 / 1024; + } + + qWarning() << "Could not get available RAM: host_statistics64"; + return 0; +} + +#elif defined(Q_OS_LINUX) +#include <fstream> + +namespace { +QString afterColon(QString& str) +{ + return str.remove(0, str.indexOf(':') + 2).trimmed(); +} +} // namespace + +QString HardwareInfo::cpuInfo() +{ + std::ifstream cpuin("/proc/cpuinfo"); + for (std::string line; std::getline(cpuin, line);) { + // model name : AMD Ryzen 7 5800X 8-Core Processor + if (QString str = QString::fromStdString(line); str.startsWith("model name")) { + return afterColon(str); + } + } + + qWarning() << "Could not get CPU model: /proc/cpuinfo"; + return "unknown"; +} + +uint64_t readMemInfo(QString searchTarget) +{ + std::ifstream memin("/proc/meminfo"); + for (std::string line; std::getline(memin, line);) { + // MemTotal: 16287480 kB + if (QString str = QString::fromStdString(line); str.startsWith(searchTarget)) { + bool ok = false; + const uint total = str.simplified().section(' ', 1, 1).toUInt(&ok); + if (!ok) { + qWarning() << "Could not read /proc/meminfo: failed to parse string:" << str; + return 0; + } + + // transforming kib -> mib + return total / 1024; + } + } + + qWarning() << "Could not read /proc/meminfo: search target not found:" << searchTarget; + return 0; +} + +uint64_t HardwareInfo::totalRamMiB() +{ + return readMemInfo("MemTotal"); +} + +uint64_t HardwareInfo::availableRamMiB() +{ + return readMemInfo("MemAvailable"); +} + +QStringList HardwareInfo::gpuInfo() +{ + QStringList list; + const bool vulkanSuccess = vulkanInfo(list); + const bool openGlSuccess = openGlInfo(list); + if (vulkanSuccess || openGlSuccess) { + return list; + } + + std::array<char, 512> buffer; + FILE* lspci = popen("lspci -k", "r"); + + if (!lspci) { + return { "Could not detect GPUs: lspci is not present" }; + } + + bool readingGpuInfo = false; + QString currentModel = ""; + while (fgets(buffer.data(), 512, lspci) != nullptr) { + QString str(buffer.data()); + // clang-format off + // 04:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7) + // Subsystem: Sapphire Technology Limited Radeon RX 580 Pulse 4GB + // Kernel driver in use: amdgpu + // Kernel modules: amdgpu + // clang-format on + if (str.contains("VGA compatible controller")) { + readingGpuInfo = true; + } else if (!str.startsWith('\t')) { + readingGpuInfo = false; + } + if (!readingGpuInfo) { + continue; + } + + if (str.contains("Subsystem")) { + currentModel = "Found GPU: " + afterColon(str); + } + if (str.contains("Kernel driver in use")) { + currentModel += " (using driver " + afterColon(str); + } + if (str.contains("Kernel modules")) { + currentModel += ", available drivers: " + afterColon(str) + ")"; + list.append(currentModel); + } + } + pclose(lspci); + return list; +} + +#else + +QString HardwareInfo::cpuInfo() +{ + return "unknown"; +} + +#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) +#include <cstdio> + +uint64_t HardwareInfo::totalRamMiB() +{ + char buff[512]; + FILE* fp = popen("sysctl hw.physmem", "r"); + if (fp != nullptr) { + if (fgets(buff, 512, fp) != nullptr) { + std::string str(buff); + uint64_t mem = std::stoull(str.substr(12, std::string::npos)); + + // transforming kib -> mib + return mem / 1024; + } + } + + return 0; +} + +#else +uint64_t HardwareInfo::totalRamMiB() +{ + return 0; +} +#endif + +uint64_t HardwareInfo::availableRamMiB() +{ + return 0; +} + +#endif |
