system-info-windows.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "system-info.hpp"
  2. #include <dxgi.h>
  3. #include <cinttypes>
  4. #include <shlobj.h>
  5. #include <util/dstr.hpp>
  6. #include <util/platform.h>
  7. #include <util/windows/ComPtr.hpp>
  8. #include <util/windows/win-registry.h>
  9. #include <util/windows/win-version.h>
  10. static std::optional<std::vector<GoLiveApi::Gpu>> system_gpu_data()
  11. {
  12. ComPtr<IDXGIFactory1> factory;
  13. ComPtr<IDXGIAdapter1> adapter;
  14. HRESULT hr;
  15. UINT i;
  16. hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
  17. if (FAILED(hr))
  18. return std::nullopt;
  19. std::vector<GoLiveApi::Gpu> adapter_info;
  20. for (i = 0; factory->EnumAdapters1(i, adapter.Assign()) == S_OK; ++i) {
  21. DXGI_ADAPTER_DESC desc;
  22. char name[512] = "";
  23. char driver_version[512] = "";
  24. hr = adapter->GetDesc(&desc);
  25. if (FAILED(hr))
  26. continue;
  27. /* ignore Microsoft's 'basic' renderer' */
  28. if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c)
  29. continue;
  30. os_wcs_to_utf8(desc.Description, 0, name, sizeof(name));
  31. GoLiveApi::Gpu data;
  32. data.model = name;
  33. data.vendor_id = desc.VendorId;
  34. data.device_id = desc.DeviceId;
  35. data.dedicated_video_memory = desc.DedicatedVideoMemory;
  36. data.shared_system_memory = desc.SharedSystemMemory;
  37. /* driver version */
  38. LARGE_INTEGER umd;
  39. hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
  40. &umd);
  41. if (SUCCEEDED(hr)) {
  42. const uint64_t version = umd.QuadPart;
  43. const uint16_t aa = (version >> 48) & 0xffff;
  44. const uint16_t bb = (version >> 32) & 0xffff;
  45. const uint16_t ccccc = (version >> 16) & 0xffff;
  46. const uint16_t ddddd = version & 0xffff;
  47. snprintf(driver_version, sizeof(driver_version),
  48. "%" PRIu16 ".%" PRIu16 ".%" PRIu16 ".%" PRIu16,
  49. aa, bb, ccccc, ddddd);
  50. data.driver_version = driver_version;
  51. }
  52. adapter_info.push_back(data);
  53. }
  54. return adapter_info;
  55. }
  56. static void get_processor_info(char **name, DWORD *speed)
  57. {
  58. HKEY key;
  59. wchar_t data[1024];
  60. DWORD size;
  61. LSTATUS status;
  62. memset(data, 0, sizeof(data));
  63. status = RegOpenKeyW(
  64. HKEY_LOCAL_MACHINE,
  65. L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
  66. if (status != ERROR_SUCCESS)
  67. return;
  68. size = sizeof(data);
  69. status = RegQueryValueExW(key, L"ProcessorNameString", NULL, NULL,
  70. (LPBYTE)data, &size);
  71. if (status == ERROR_SUCCESS) {
  72. os_wcs_to_utf8_ptr(data, 0, name);
  73. } else {
  74. *name = 0;
  75. }
  76. size = sizeof(*speed);
  77. status = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE)speed,
  78. &size);
  79. if (status != ERROR_SUCCESS)
  80. *speed = 0;
  81. RegCloseKey(key);
  82. }
  83. #define WIN10_GAME_BAR_REG_KEY \
  84. L"Software\\Microsoft\\Windows\\CurrentVersion\\GameDVR"
  85. #define WIN10_GAME_DVR_POLICY_REG_KEY \
  86. L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
  87. #define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
  88. #define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
  89. #define WIN10_HAGS_REG_KEY \
  90. L"SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers"
  91. static std::optional<GoLiveApi::GamingFeatures>
  92. get_gaming_features_data(const win_version_info &ver)
  93. {
  94. uint32_t win_ver = (ver.major << 8) | ver.minor;
  95. if (win_ver < 0xA00)
  96. return std::nullopt;
  97. GoLiveApi::GamingFeatures gaming_features;
  98. struct feature_mapping_s {
  99. std::optional<bool> *field;
  100. HKEY hkey;
  101. LPCWSTR sub_key;
  102. LPCWSTR value_name;
  103. LPCWSTR backup_value_name;
  104. bool non_existence_is_false;
  105. DWORD disabled_value;
  106. };
  107. struct feature_mapping_s features[] = {
  108. {&gaming_features.game_bar_enabled, HKEY_CURRENT_USER,
  109. WIN10_GAME_BAR_REG_KEY, L"AppCaptureEnabled", 0, false, 0},
  110. {&gaming_features.game_dvr_allowed, HKEY_CURRENT_USER,
  111. WIN10_GAME_DVR_POLICY_REG_KEY, L"AllowGameDVR", 0, false, 0},
  112. {&gaming_features.game_dvr_enabled, HKEY_CURRENT_USER,
  113. WIN10_GAME_DVR_REG_KEY, L"GameDVR_Enabled", 0, false, 0},
  114. {&gaming_features.game_dvr_bg_recording, HKEY_CURRENT_USER,
  115. WIN10_GAME_BAR_REG_KEY, L"HistoricalCaptureEnabled", 0, false,
  116. 0},
  117. {&gaming_features.game_mode_enabled, HKEY_CURRENT_USER,
  118. WIN10_GAME_MODE_REG_KEY, L"AutoGameModeEnabled",
  119. L"AllowAutoGameMode", false, 0},
  120. {&gaming_features.hags_enabled, HKEY_LOCAL_MACHINE,
  121. WIN10_HAGS_REG_KEY, L"HwSchMode", 0, true, 1}};
  122. for (int i = 0; i < sizeof(features) / sizeof(*features); ++i) {
  123. struct reg_dword info;
  124. get_reg_dword(features[i].hkey, features[i].sub_key,
  125. features[i].value_name, &info);
  126. if (info.status != ERROR_SUCCESS &&
  127. features[i].backup_value_name) {
  128. get_reg_dword(features[i].hkey, features[i].sub_key,
  129. features[i].backup_value_name, &info);
  130. }
  131. if (info.status == ERROR_SUCCESS) {
  132. *features[i].field = info.return_value !=
  133. features[i].disabled_value;
  134. } else if (features[i].non_existence_is_false) {
  135. *features[i].field = false;
  136. }
  137. }
  138. return gaming_features;
  139. }
  140. static inline bool get_reg_sz(HKEY key, const wchar_t *val, wchar_t *buf,
  141. DWORD size)
  142. {
  143. const LSTATUS status =
  144. RegGetValueW(key, NULL, val, RRF_RT_REG_SZ, NULL, buf, &size);
  145. return status == ERROR_SUCCESS;
  146. }
  147. #define MAX_SZ_LEN 256
  148. #define WINVER_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
  149. static char win_release_id[MAX_SZ_LEN] = "unavailable";
  150. static inline void get_reg_ver(struct win_version_info *ver)
  151. {
  152. HKEY key;
  153. DWORD size, dw_val;
  154. LSTATUS status;
  155. wchar_t str[MAX_SZ_LEN];
  156. status = RegOpenKeyW(HKEY_LOCAL_MACHINE, WINVER_REG_KEY, &key);
  157. if (status != ERROR_SUCCESS)
  158. return;
  159. size = sizeof(dw_val);
  160. status = RegQueryValueExW(key, L"CurrentMajorVersionNumber", NULL, NULL,
  161. (LPBYTE)&dw_val, &size);
  162. if (status == ERROR_SUCCESS)
  163. ver->major = (int)dw_val;
  164. status = RegQueryValueExW(key, L"CurrentMinorVersionNumber", NULL, NULL,
  165. (LPBYTE)&dw_val, &size);
  166. if (status == ERROR_SUCCESS)
  167. ver->minor = (int)dw_val;
  168. status = RegQueryValueExW(key, L"UBR", NULL, NULL, (LPBYTE)&dw_val,
  169. &size);
  170. if (status == ERROR_SUCCESS)
  171. ver->revis = (int)dw_val;
  172. if (get_reg_sz(key, L"CurrentBuildNumber", str, sizeof(str))) {
  173. ver->build = wcstol(str, NULL, 10);
  174. }
  175. const wchar_t *release_key = ver->build > 19041 ? L"DisplayVersion"
  176. : L"ReleaseId";
  177. if (get_reg_sz(key, release_key, str, sizeof(str))) {
  178. os_wcs_to_utf8(str, 0, win_release_id, MAX_SZ_LEN);
  179. }
  180. RegCloseKey(key);
  181. }
  182. void system_info(GoLiveApi::Capabilities &capabilities)
  183. {
  184. char tmpstr[1024];
  185. capabilities.gpu = system_gpu_data();
  186. {
  187. auto &cpu_data = capabilities.cpu;
  188. cpu_data.physical_cores = os_get_physical_cores();
  189. cpu_data.logical_cores = os_get_logical_cores();
  190. DWORD processorSpeed;
  191. char *processorName;
  192. get_processor_info(&processorName, &processorSpeed);
  193. if (processorSpeed)
  194. cpu_data.speed = processorSpeed;
  195. if (processorName)
  196. cpu_data.name = processorName;
  197. bfree(processorName);
  198. }
  199. {
  200. auto &memory_data = capabilities.memory;
  201. memory_data.total = os_get_sys_total_size();
  202. memory_data.free = os_get_sys_free_size();
  203. }
  204. struct win_version_info ver;
  205. get_win_ver(&ver);
  206. get_reg_ver(&ver);
  207. // Gaming features
  208. capabilities.gaming_features = get_gaming_features_data(ver);
  209. {
  210. auto &system_data = capabilities.system;
  211. snprintf(tmpstr, sizeof(tmpstr), "%d.%d", ver.major, ver.minor);
  212. system_data.version = tmpstr;
  213. system_data.name = "Windows";
  214. system_data.build = ver.build;
  215. system_data.release = win_release_id;
  216. system_data.revision = ver.revis;
  217. system_data.bits = is_64_bit_windows() ? 64 : 32;
  218. system_data.arm = is_arm64_windows();
  219. system_data.armEmulation = os_get_emulation_status();
  220. }
  221. }