system-info-windows.cpp 7.4 KB

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