From 16f76fa04bf303523bd55d6f54574c17685f4204 Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Mon, 2 Aug 2021 02:26:18 +0200 Subject: [PATCH] Extend SystemInfo --- openVulkanoCpp/Host/Linux/SystemInfo.cpp | 254 +++++++++++++++++++++ openVulkanoCpp/Host/SystemInfo.hpp | 54 ++++- openVulkanoCpp/Host/Windows/SystemInfo.cpp | 157 +++++++++++++ openVulkanoCpp/Host/iOS/SystemInfo.mm | 195 ++++++++++++++++ 4 files changed, 659 insertions(+), 1 deletion(-) diff --git a/openVulkanoCpp/Host/Linux/SystemInfo.cpp b/openVulkanoCpp/Host/Linux/SystemInfo.cpp index 97101db..9eb2375 100644 --- a/openVulkanoCpp/Host/Linux/SystemInfo.cpp +++ b/openVulkanoCpp/Host/Linux/SystemInfo.cpp @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include namespace openVulkanoCpp { @@ -103,4 +105,256 @@ namespace openVulkanoCpp Logger::PERF->error("Failed to query max application memory"); return 0; } + + std::string SystemInfo::GetUserName() + { + char* name = getlogin(); + if (!name) return "unknown"; + return name; + } + + std::string SystemInfo::GetHostName() + { + char hostname[HOST_NAME_MAX + 1]; + gethostname(hostname, HOST_NAME_MAX + 1); + return hostname; + } + + std::string SystemInfo::GetDeviceName() + { + return GetHostName(); + } + + std::string SystemInfo::GetDeviceVendorName() + { + std::ifstream dmiStream("/sys/class/dmi/id/board_vendor"); + if (!dmiStream) + { + Logger::PERF->error("Failed to read /sys/class/dmi/id/board_vendor"); + return "Unknown"; + } + + std::string motherboardName; + std::getline(dmiStream, motherboardName); + return motherboardName; + } + + std::string SystemInfo::GetDeviceModelName() + { + std::ifstream dmiStream("/sys/class/dmi/id/board_name"); + if (!dmiStream) + { + Logger::PERF->error("Failed to read /sys/class/dmi/id/board_name"); + return "Unknown"; + } + + std::string motherboardName; + std::getline(dmiStream, motherboardName); + return motherboardName; + } + + namespace + { + struct OsInfo + { + std::string osName, osNameFormatted; + Version version; + + static std::string TryRead(const std::string line, std::string_view prefix) + { + if (Utils::StartsWith(line, prefix)) + { + size_t prefixLen = prefix.length(); + return line.substr(prefixLen, line.length() - prefixLen - 1); + } + return ""; + } + + static Version ParseVersionString(char* str) + { + int ver[3]; + int i = 0; + + while (*str && i < 3) + { + if (isdigit(*str)) + { + ver[i] = strtol(str, &str, 10); + i++; + } + else + { + str++; + } + } + return {ver[0], ver[1], ver[2], 0}; + } + + OsInfo() : version({0, 0, 0, 0}) + { + std::ifstream osRel("/etc/os-release"); + std::string versionString; + if (osRel) + { + std::string line, name, tmp; + while (std::getline(osRel, line)) + { + if (!(tmp = TryRead(line, "PRETTY_NAME=\"")).empty()) + { + osName = std::move(tmp); + } + else if (!(tmp = TryRead(line, "NAME=\"")).empty()) + { + name = std::move(tmp); + } + else if (name.empty() && Utils::StartsWith(line, "ID=\"")) + { + name = line.substr(4, line.length() - 5); + } + else if (!(tmp = TryRead(line, "BUILD_ID=\"")).empty()) + { + versionString = std::move(tmp); + } + else if (!(tmp = TryRead(line, "VERSION_ID=\"")).empty()) + { + versionString = std::move(tmp); + } + } + if (osName.empty()) osName = name; + osNameFormatted = osName + " " + versionString; + if (!versionString.empty()) version = ParseVersionString(versionString.data()); + } + if (osName.empty() || versionString.empty()) + { // fallback to uname + struct utsname buffer; + + errno = 0; + if (uname(&buffer) == 0) + { + osName = buffer.sysname; + osNameFormatted = osName + " " + buffer.release; + + version = ParseVersionString(buffer.release); + return; + } + perror("uname"); + } + if (osName.empty()) osName = "Linux"; + if (osNameFormatted.empty()) osNameFormatted = "Linux"; + } + }; + + OsInfo osInfo; + } + + std::string SystemInfo::GetOsName() + { + return osInfo.osName; + } + + Version SystemInfo::GetOsVersion() + { + return osInfo.version; + } + + std::string SystemInfo::GetOsNameHumanReadable() + { + return osInfo.osNameFormatted; + } + + DeviceType SystemInfo::GetDeviceType() + { + return DeviceType::PC; // TODO? + } + + size_t SystemInfo::GetCpuCoreCount() + { + return 0; //TODO + } + + size_t SystemInfo::GetCpuThreadCount() + { + return std::thread::hardware_concurrency(); + } + + int32_t SystemInfo::GetCpuTemperature() + { + std::ifstream tempFile("/sys/class/thermal/thermal_zone0/temp"); + if (!tempFile) + { + Logger::PERF->error("Failed to open the temperature file"); + return 20; + } + + std::string tempStr; + std::getline(tempFile, tempStr); + + return static_cast(std::stof(tempStr) / 1000.0f); + } + + CpuThermalState SystemInfo::GetCpuThermalState() + { + auto temp = GetCpuTemperature(); + if (temp < 70) return CpuThermalState::Normal; + if (temp < 80) return CpuThermalState::Fair; + if (temp < 95) return CpuThermalState::Serious; + return CpuThermalState::Critical; + } + + bool SystemInfo::IsDeviceInLowPowerMode() + { + return false; //TODO? + } + + BatteryState SystemInfo::GetDeviceBatteryState() + { + std::ifstream powerSupplyFile("/sys/class/power_supply/BAT0/status"); + if (powerSupplyFile) + { + std::string status; + std::getline(powerSupplyFile, status); + if (status == "Charging") return BatteryState::Charging; + if (status == "Not charging") return BatteryState::NotCharging; + if (status == "Full") return BatteryState::ChargingFull; + if (status == "Discharging") return BatteryState::Unplugged; + } + return BatteryState::Unavailable; + } + + float SystemInfo::GetDeviceBatteryLevel() + { + std::ifstream powerSupplyFile("/sys/class/power_supply/BAT0/capacity"); + if (powerSupplyFile) + { + float value; + powerSupplyFile >> value; + return value; + } + return 0; + } + + void SystemInfo::EnableEnergyEvents() + { + //TODO + } + + bool SystemInfo::IsMultitaskingSupported() + { + return true; + } + + DeviceOrientation SystemInfo::GetDeviceOrientation() + { + return DeviceOrientation::LandscapeRight; // TODO? + } + + void SystemInfo::EnableDeviceOrientationEvents() + { + //TODO? + } + + InterfaceOrientation SystemInfo::GetInterfaceOrientation() + { + return InterfaceOrientation::Landscape; // TODO? + } } \ No newline at end of file diff --git a/openVulkanoCpp/Host/SystemInfo.hpp b/openVulkanoCpp/Host/SystemInfo.hpp index bdf3b04..ebd3d6d 100644 --- a/openVulkanoCpp/Host/SystemInfo.hpp +++ b/openVulkanoCpp/Host/SystemInfo.hpp @@ -4,10 +4,26 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include +#include "Base/Event.hpp" +#include namespace openVulkanoCpp { + struct Version + { + int major, minor, patch, build; + }; + + enum class DeviceType { Phone, Tablet, PC, TV, VR, Unknown }; + + enum class CpuThermalState { Normal, Fair, Serious, Critical }; + + enum class BatteryState { Unavailable, Unplugged, Charging, ChargingFull, NotCharging }; + + enum class DeviceOrientation { Portrait, PortraitUpsideDown, LandscapeLeft, LandscapeRight, FaceUp, FaceDown, Unknown }; + + enum class InterfaceOrientation { Portrait, PortraitUpsideDown, LandscapeLeft, LandscapeRight, Landscape = LandscapeLeft }; + class SystemInfo { public: @@ -17,5 +33,41 @@ namespace openVulkanoCpp static size_t GetAppVirtualMemoryMax(); static size_t GetAppRamAvailable(); static size_t GetAppRamUsed(); + + static std::string GetUserName(); + static std::string GetHostName(); + static std::string GetDeviceName(); + static std::string GetDeviceVendorName(); + static std::string GetDeviceModelName(); + static std::string GetOsName(); + static Version GetOsVersion(); + static std::string GetOsNameHumanReadable(); + static DeviceType GetDeviceType(); + + static size_t GetCpuCoreCount(); + static size_t GetCpuThreadCount(); + static int32_t GetCpuTemperature(); + static CpuThermalState GetCpuThermalState(); + + static bool IsDeviceInLowPowerMode(); + static bool GetDeviceHasBattery() { return GetDeviceBatteryState() != BatteryState::Unavailable; } + static BatteryState GetDeviceBatteryState(); + static float GetDeviceBatteryLevel(); + static void EnableEnergyEvents(); + + /** + * Checks if device allows to run multiple applications at the same time. + * Will probably return true, for everything but smartphones. + * @return true if multiple applications can run at the same time, false if not + */ + static bool IsMultitaskingSupported(); + static DeviceOrientation GetDeviceOrientation(); + static void EnableDeviceOrientationEvents(); + static InterfaceOrientation GetInterfaceOrientation(); + + static Event<> OnLowPowerModeChanged; + static Event<> OnBatteryStateChanged; + static Event<> OnBatteryLevelChanged; + static Event<> OnDeviceOrientationChanged; }; } diff --git a/openVulkanoCpp/Host/Windows/SystemInfo.cpp b/openVulkanoCpp/Host/Windows/SystemInfo.cpp index be485a2..5a78208 100644 --- a/openVulkanoCpp/Host/Windows/SystemInfo.cpp +++ b/openVulkanoCpp/Host/Windows/SystemInfo.cpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include namespace openVulkanoCpp { @@ -79,4 +82,158 @@ namespace openVulkanoCpp { return ReadAppMemInfo(APP_MEM_TYPE::VM_MAX); } + + std::string SystemInfo::GetUserName() + { + char username[UNLEN+1]; + DWORD username_len = UNLEN+1; + GetUserName(username, &username_len); + return username; + } + + std::string SystemInfo::GetHostName() + { + char hostname[UNLEN+1]; + gethostname(hostname, UNLEN+1); + return hostname; + } + + std::string SystemInfo::GetDeviceName() + { + char computerName[UNLEN+1]; + DWORD computerName_len = UNLEN+1; + GetComputerNameA(computerName, &computerName_len); + return computerName; + } + + std::string SystemInfo::GetDeviceVendorName() + { + return "Microsoft"; //TODO + } + + std::string SystemInfo::GetDeviceModelName() + { + return "Unknown"; //TODO + } + + std::string SystemInfo::GetOsName() + { + return "Windows"; + } + + Version SystemInfo::GetOsVersion() + { + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx(&info); + return { info.dwMajorVersion, info.dwMinorVersion, 0, info.dwBuildNumber }; + } + + std::string SystemInfo::GetOsNameHumanReadable() + { + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx(&info); + if (info.wProductType == VER_NT_WORKSTATION) + { + if (info.dwMajorVersion == 10) + return "Windows 10"; + else if (info.dwMajorVersion == 6) + { + switch (info.dwMinorVersion) + { + case 0: return "Windows Vista"; + case 1: return "Windows 7"; + case 2: return "Windows 8"; + case 3: return "Windows 8.1"; + } + } + + return "Windows " + std::string(info.dwMajorVersion) + "." + std::string(info.dwMinorVersion); + } + else + { + if (info.dwMajorVersion == 10) + return "Windows Server 2016"; + else if (info.dwMajorVersion == 6) + { + switch (info.dwMinorVersion) + { + case 0: return "Windows Server 2008"; + case 1: return "Windows Server 2008 R2"; + case 2: return "Windows Server 2012"; + case 3: return "Windows Server 2012 R2"; + } + } + + return "Windows Server " + std::string(info.dwMajorVersion) + "." + std::string(info.dwMinorVersion); + } + } + + DeviceType SystemInfo::GetDeviceType() + { + return DeviceType::PC; + } + + size_t SystemInfo::GetCpuCoreCount() + { + return 0; //TODO + } + + size_t SystemInfo::GetCpuThreadCount() + { + return std::thread::hardware_concurrency(); + } + + int32_t SystemInfo::GetCpuTemperature() + { + return 0; //TODO + } + + CpuThermalState SystemInfo::GetCpuThermalState() + { + return CpuThermalState::Normal; + } + + bool SystemInfo::IsDeviceInLowPowerMode() + { + return false; //TODO + } + + BatteryState SystemInfo::GetDeviceBatteryState() + { + return BatteryState::Unavailable; //TODO + } + + float SystemInfo::GetDeviceBatteryLevel() + { + return 0; //TODO + } + + void SystemInfo::EnableEnergyEvents() + { + //TODO + } + + bool SystemInfo::IsMultitaskingSupported() + { + return true; + } + + DeviceOrientation SystemInfo::GetDeviceOrientation() + { + return DeviceOrientation::LandscapeRight; //TODO + } + + void SystemInfo::EnableDeviceOrientationEvents() + { + //TODO + } + + InterfaceOrientation SystemInfo::GetInterfaceOrientation() + { + return InterfaceOrientation::Landscape; //TODO + } } \ No newline at end of file diff --git a/openVulkanoCpp/Host/iOS/SystemInfo.mm b/openVulkanoCpp/Host/iOS/SystemInfo.mm index 54d44fe..6f13701 100644 --- a/openVulkanoCpp/Host/iOS/SystemInfo.mm +++ b/openVulkanoCpp/Host/iOS/SystemInfo.mm @@ -6,13 +6,23 @@ #include "Host/SystemInfo.hpp" #include "Base/Logger.hpp" +#include + #include #include #import +#import +#import +#import namespace openVulkanoCpp { + Event<> SystemInfo::OnLowPowerModeChanged; + Event<> SystemInfo::OnBatteryStateChanged; + Event<> SystemInfo::OnBatteryLevelChanged; + Event<> SystemInfo::OnDeviceOrientationChanged; + size_t SystemInfo::GetSystemRam() { return [NSProcessInfo processInfo].physicalMemory; @@ -50,4 +60,189 @@ namespace openVulkanoCpp Logger::PERF->error("Failed to read memory consumption: {}", mach_error_string(kerr)); return 0; } + + std::string SystemInfo::GetUserName() + { + return ""; + } + + std::string SystemInfo::GetHostName() + { + return [[NSProcessInfo processInfo].hostName UTF8String]; + } + + std::string SystemInfo::GetDeviceName() + { + return [[[UIDevice currentDevice] name] UTF8String]; + } + + std::string SystemInfo::GetDeviceVendorName() + { + return "Apple"; + } + + std::string SystemInfo::GetDeviceModelName() + { + return [[[UIDevice currentDevice] model] UTF8String]; + } + + std::string SystemInfo::GetOsName() + { + return [[[UIDevice currentDevice] systemName] UTF8String]; + } + + Version SystemInfo::GetOsVersion() + { + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + return { static_cast(osVersion.majorVersion), static_cast(osVersion.minorVersion), static_cast(osVersion.patchVersion), 0 }; + } + + std::string SystemInfo::GetOsNameHumanReadable() + { + std::stringstream name; + name << GetOsName() << ' ' << GetOsVersion().major; + return name.str(); + } + + DeviceType SystemInfo::GetDeviceType() + { + switch ([UIDevice currentDevice].userInterfaceIdiom) + { + case UIUserInterfaceIdiomPhone: return DeviceType::Phone; + case UIUserInterfaceIdiomPad: return DeviceType::Tablet; + case UIUserInterfaceIdiomTV: return DeviceType::TV; + case UIUserInterfaceIdiomMac: return DeviceType::PC; + case UIUserInterfaceIdiomVision: return DeviceType::VR; + } + return DeviceType::Unknown; + } + + size_t SystemInfo::GetCpuCoreCount() + { + return [NSProcessInfo processInfo].processorCount; + } + + size_t SystemInfo::GetCpuThreadCount() + { + return [NSProcessInfo processInfo].activeProcessorCount; + } + + int32_t SystemInfo::GetCpuTemperature() + { + switch([NSProcessInfo processInfo].thermalState) + { + case NSProcessInfoThermalStateNominal: return 20; + case NSProcessInfoThermalStateFair: return 50; + case NSProcessInfoThermalStateSerious: return 80; + case NSProcessInfoThermalStateCritical: return 100; + } + return -1; + } + + CpuThermalState SystemInfo::GetCpuThermalState() + { + switch([NSProcessInfo processInfo].thermalState) + { + case NSProcessInfoThermalStateNominal: return CpuThermalState::Normal; + case NSProcessInfoThermalStateFair: return CpuThermalState::Fair; + case NSProcessInfoThermalStateSerious: return CpuThermalState::Serious; + case NSProcessInfoThermalStateCritical: return CpuThermalState::Critical; + } + return CpuThermalState::Normal; + } + + bool SystemInfo::IsDeviceInLowPowerMode() + { + return [NSProcessInfo processInfo].lowPowerModeEnabled; + } + + void SystemInfo::EnableEnergyEvents() + { + [[NSNotificationCenter defaultCenter] addObserverForName:NSProcessInfoPowerStateDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + SystemInfo::OnLowPowerModeChanged.NotifyAll(); + }]; + [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceBatteryLevelDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + SystemInfo::OnBatteryLevelChanged.NotifyAll(); + }]; + [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceBatteryStateDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + SystemInfo::OnBatteryStateChanged.NotifyAll(); + }]; + } + + BatteryState SystemInfo::GetDeviceBatteryState() + { + switch([UIDevice currentDevice].batteryState) + { + case UIDeviceBatteryStateUnplugged: return BatteryState::Unplugged; + case UIDeviceBatteryStateCharging: return BatteryState::Charging; + case UIDeviceBatteryStateFull: return BatteryState::ChargingFull; + } + return BatteryState::Unavailable; + } + + float SystemInfo::GetDeviceBatteryLevel() + { + return [UIDevice currentDevice].batteryLevel; + } + + bool SystemInfo::IsMultitaskingSupported() + { + return [UIDevice currentDevice].multitaskingSupported; + } + + DeviceOrientation SystemInfo::GetDeviceOrientation() + { + switch([UIDevice currentDevice].orientation) + { + case UIDeviceOrientationPortrait: return DeviceOrientation::Portrait; + case UIDeviceOrientationPortraitUpsideDown: return DeviceOrientation::PortraitUpsideDown; + case UIDeviceOrientationLandscapeLeft: return DeviceOrientation::LandscapeLeft; + case UIDeviceOrientationLandscapeRight: return DeviceOrientation::LandscapeRight; + case UIDeviceOrientationFaceUp: return DeviceOrientation::FaceUp; + case UIDeviceOrientationFaceDown: return DeviceOrientation::FaceDown; + } + return DeviceOrientation::Unknown; + } + + void SystemInfo::EnableDeviceOrientationEvents() + { + [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + SystemInfo::OnDeviceOrientationChanged.NotifyAll(); + }]; + [[UIDevice currentDevice]beginGeneratingDeviceOrientationNotifications]; + } + + InterfaceOrientation SystemInfo::GetInterfaceOrientation() + { + if (@available(iOS 15.0, *)) + { //TODO support multi scene at some point + UIInterfaceOrientation interfaceOrientation; + for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) + { + if ([scene isKindOfClass:[UIWindowScene class]]) + { + interfaceOrientation = ((UIWindowScene *)scene).interfaceOrientation; + break; + } + } + switch(interfaceOrientation) + { + case UIInterfaceOrientationPortrait: return InterfaceOrientation::Portrait; + case UIInterfaceOrientationPortraitUpsideDown: return InterfaceOrientation::PortraitUpsideDown; + case UIInterfaceOrientationLandscapeLeft: return InterfaceOrientation::LandscapeLeft; + case UIInterfaceOrientationLandscapeRight: return InterfaceOrientation::LandscapeRight; + } + } + else + { + switch(GetDeviceOrientation()) + { + case DeviceOrientation::Portrait: return InterfaceOrientation::Portrait; + case DeviceOrientation::PortraitUpsideDown: return InterfaceOrientation::PortraitUpsideDown; + case DeviceOrientation::LandscapeLeft: return InterfaceOrientation::LandscapeRight; + case DeviceOrientation::LandscapeRight: return InterfaceOrientation::LandscapeLeft; + } + } + return InterfaceOrientation::Landscape; + } }