Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "lib/svn_revision.h"
21 : #include "lib/timer.h"
22 : #include "lib/utf8.h"
23 : #include "lib/external_libraries/libsdl.h"
24 : #include "lib/posix/posix_utsname.h"
25 : #include "lib/sysdep/cpu.h"
26 : #include "lib/sysdep/numa.h"
27 : #include "lib/sysdep/os_cpu.h"
28 : #if CONFIG2_AUDIO
29 : #include "soundmanager/SoundManager.h"
30 : #endif
31 : #include "ps/CLogger.h"
32 : #include "ps/ConfigDB.h"
33 : #include "ps/Filesystem.h"
34 : #include "ps/GameSetup/Config.h"
35 : #include "ps/Profile.h"
36 : #include "ps/scripting/JSInterface_ConfigDB.h"
37 : #include "ps/scripting/JSInterface_Debug.h"
38 : #include "ps/UserReport.h"
39 : #include "ps/VideoMode.h"
40 : #include "renderer/backend/IDevice.h"
41 : #include "scriptinterface/FunctionWrapper.h"
42 : #include "scriptinterface/JSON.h"
43 : #include "scriptinterface/Object.h"
44 : #include "scriptinterface/ScriptInterface.h"
45 :
46 : // FreeType headers might have an include order.
47 : #include <ft2build.h>
48 : #include <freetype/freetype.h>
49 :
50 : #if OS_LINUX
51 : #include <fstream>
52 : #endif
53 :
54 : #include <sstream>
55 : #include <string>
56 : #include <thread>
57 :
58 : static void ReportSDL(const ScriptRequest& rq, JS::HandleValue settings);
59 : static void ReportFreeType(const ScriptRequest& rq, JS::HandleValue settings);
60 :
61 0 : void SetDisableAudio(bool disabled)
62 : {
63 0 : g_DisableAudio = disabled;
64 0 : }
65 :
66 0 : void RunHardwareDetection()
67 : {
68 0 : TIMER(L"RunHardwareDetection");
69 :
70 0 : ScriptInterface scriptInterface("Engine", "HWDetect", g_ScriptContext);
71 :
72 0 : ScriptRequest rq(scriptInterface);
73 :
74 0 : JSI_Debug::RegisterScriptFunctions(scriptInterface); // Engine.DisplayErrorDialog
75 0 : JSI_ConfigDB::RegisterScriptFunctions(scriptInterface);
76 :
77 0 : ScriptFunction::Register<SetDisableAudio>(rq, "SetDisableAudio");
78 :
79 : // Load the detection script:
80 :
81 0 : const wchar_t* scriptName = L"hwdetect/hwdetect.js";
82 0 : CVFSFile file;
83 0 : if (file.Load(g_VFS, scriptName) != PSRETURN_OK)
84 : {
85 0 : LOGERROR("Failed to load hardware detection script");
86 0 : return;
87 : }
88 :
89 0 : std::string code = file.DecodeUTF8(); // assume it's UTF-8
90 0 : scriptInterface.LoadScript(scriptName, code);
91 :
92 : // Collect all the settings we'll pass to the script:
93 : // (We'll use this same data for the opt-in online reporting system, so it
94 : // includes some fields that aren't directly useful for the hwdetect script)
95 :
96 0 : JS::RootedValue settings(rq.cx);
97 0 : Script::CreateObject(rq, &settings);
98 :
99 0 : Script::SetProperty(rq, settings, "os_unix", OS_UNIX);
100 0 : Script::SetProperty(rq, settings, "os_bsd", OS_BSD);
101 0 : Script::SetProperty(rq, settings, "os_linux", OS_LINUX);
102 0 : Script::SetProperty(rq, settings, "os_android", OS_ANDROID);
103 0 : Script::SetProperty(rq, settings, "os_macosx", OS_MACOSX);
104 0 : Script::SetProperty(rq, settings, "os_win", OS_WIN);
105 :
106 0 : Script::SetProperty(rq, settings, "arch_ia32", ARCH_IA32);
107 0 : Script::SetProperty(rq, settings, "arch_amd64", ARCH_AMD64);
108 0 : Script::SetProperty(rq, settings, "arch_arm", ARCH_ARM);
109 0 : Script::SetProperty(rq, settings, "arch_aarch64", ARCH_AARCH64);
110 0 : Script::SetProperty(rq, settings, "arch_e2k", ARCH_E2K);
111 0 : Script::SetProperty(rq, settings, "arch_ppc64", ARCH_PPC64);
112 :
113 : #ifdef NDEBUG
114 : Script::SetProperty(rq, settings, "build_debug", 0);
115 : #else
116 0 : Script::SetProperty(rq, settings, "build_debug", 1);
117 : #endif
118 0 : Script::SetProperty(rq, settings, "build_opengles", CONFIG2_GLES);
119 :
120 0 : Script::SetProperty(rq, settings, "build_datetime", std::string(__DATE__ " " __TIME__));
121 0 : Script::SetProperty(rq, settings, "build_revision", std::wstring(svn_revision));
122 :
123 0 : Script::SetProperty(rq, settings, "build_msc", (int)MSC_VERSION);
124 0 : Script::SetProperty(rq, settings, "build_icc", (int)ICC_VERSION);
125 0 : Script::SetProperty(rq, settings, "build_gcc", (int)GCC_VERSION);
126 0 : Script::SetProperty(rq, settings, "build_clang", (int)CLANG_VERSION);
127 :
128 0 : Script::SetProperty(rq, settings, "gfx_card", g_VideoMode.GetBackendDevice()->GetName());
129 0 : Script::SetProperty(rq, settings, "gfx_drv_ver", g_VideoMode.GetBackendDevice()->GetDriverInformation());
130 : #if CONFIG2_AUDIO
131 0 : if (g_SoundManager)
132 : {
133 0 : Script::SetProperty(rq, settings, "snd_card", g_SoundManager->GetSoundCardNames());
134 0 : Script::SetProperty(rq, settings, "snd_drv_ver", g_SoundManager->GetOpenALVersion());
135 : }
136 : #endif
137 0 : ReportSDL(rq, settings);
138 :
139 0 : ReportFreeType(rq, settings);
140 :
141 0 : JS::RootedValue backendDeviceSettings(rq.cx);
142 0 : Script::CreateObject(rq, &backendDeviceSettings);
143 :
144 0 : g_VideoMode.GetBackendDevice()->Report(rq, backendDeviceSettings);
145 0 : Script::SetProperty(rq, settings, "renderer_backend", backendDeviceSettings);
146 :
147 0 : Script::SetProperty(rq, settings, "video_desktop_xres", g_VideoMode.GetDesktopXRes());
148 0 : Script::SetProperty(rq, settings, "video_desktop_yres", g_VideoMode.GetDesktopYRes());
149 0 : Script::SetProperty(rq, settings, "video_desktop_bpp", g_VideoMode.GetDesktopBPP());
150 0 : Script::SetProperty(rq, settings, "video_desktop_freq", g_VideoMode.GetDesktopFreq());
151 :
152 : struct utsname un;
153 0 : uname(&un);
154 0 : Script::SetProperty(rq, settings, "uname_sysname", std::string(un.sysname));
155 0 : Script::SetProperty(rq, settings, "uname_release", std::string(un.release));
156 0 : Script::SetProperty(rq, settings, "uname_version", std::string(un.version));
157 0 : Script::SetProperty(rq, settings, "uname_machine", std::string(un.machine));
158 :
159 : #if OS_LINUX
160 : {
161 0 : std::ifstream ifs("/etc/lsb-release");
162 0 : if (ifs.good())
163 : {
164 0 : std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
165 0 : Script::SetProperty(rq, settings, "linux_release", str);
166 : }
167 : }
168 : #endif
169 :
170 0 : Script::SetProperty(rq, settings, "cpu_identifier", std::string(cpu_IdentifierString()));
171 0 : Script::SetProperty(rq, settings, "cpu_frequency", os_cpu_ClockFrequency());
172 0 : Script::SetProperty(rq, settings, "cpu_pagesize", (u32)os_cpu_PageSize());
173 0 : Script::SetProperty(rq, settings, "cpu_largepagesize", (u32)os_cpu_LargePageSize());
174 0 : Script::SetProperty(rq, settings, "cpu_numprocs", (u32)os_cpu_NumProcessors());
175 :
176 0 : Script::SetProperty(rq, settings, "numa_numnodes", (u32)numa_NumNodes());
177 0 : Script::SetProperty(rq, settings, "numa_factor", numa_Factor());
178 0 : Script::SetProperty(rq, settings, "numa_interleaved", numa_IsMemoryInterleaved());
179 :
180 0 : Script::SetProperty(rq, settings, "ram_total", (u32)os_cpu_MemorySize());
181 0 : Script::SetProperty(rq, settings, "ram_total_os", (u32)os_cpu_QueryMemorySize());
182 :
183 : #if ARCH_X86_X64
184 0 : Script::SetProperty(rq, settings, "x86_vendor", (u32)x86_x64::Vendor());
185 0 : Script::SetProperty(rq, settings, "x86_model", (u32)x86_x64::Model());
186 0 : Script::SetProperty(rq, settings, "x86_family", (u32)x86_x64::Family());
187 :
188 : u32 caps0, caps1, caps2, caps3;
189 0 : x86_x64::GetCapBits(&caps0, &caps1, &caps2, &caps3);
190 0 : Script::SetProperty(rq, settings, "x86_caps[0]", caps0);
191 0 : Script::SetProperty(rq, settings, "x86_caps[1]", caps1);
192 0 : Script::SetProperty(rq, settings, "x86_caps[2]", caps2);
193 0 : Script::SetProperty(rq, settings, "x86_caps[3]", caps3);
194 : #endif
195 :
196 0 : Script::SetProperty(rq, settings, "timer_resolution", timer_Resolution());
197 :
198 0 : Script::SetProperty(rq, settings, "hardware_concurrency", std::thread::hardware_concurrency());
199 :
200 : // The version should be increased for every meaningful change.
201 0 : const int reportVersion = 20;
202 :
203 : // Send the same data to the reporting system
204 0 : g_UserReporter.SubmitReport(
205 : "hwdetect",
206 : reportVersion,
207 0 : Script::StringifyJSON(rq, &settings, false),
208 0 : Script::StringifyJSON(rq, &settings, true));
209 :
210 : // Run the detection script:
211 0 : JS::RootedValue global(rq.cx, rq.globalValue());
212 0 : ScriptFunction::CallVoid(rq, global, "RunHardwareDetection", settings);
213 : }
214 :
215 0 : static void ReportSDL(const ScriptRequest& rq, JS::HandleValue settings)
216 : {
217 : SDL_version build, runtime;
218 0 : SDL_VERSION(&build);
219 :
220 : char version[16];
221 0 : snprintf(version, ARRAY_SIZE(version), "%d.%d.%d", build.major, build.minor, build.patch);
222 0 : Script::SetProperty(rq, settings, "sdl_build_version", version);
223 :
224 0 : SDL_GetVersion(&runtime);
225 0 : snprintf(version, ARRAY_SIZE(version), "%d.%d.%d", runtime.major, runtime.minor, runtime.patch);
226 0 : Script::SetProperty(rq, settings, "sdl_runtime_version", version);
227 :
228 : // This is null in atlas (and further the call triggers an assertion).
229 0 : const char* backend = g_VideoMode.GetWindow() ? GetSDLSubsystem(g_VideoMode.GetWindow()) : "none";
230 0 : Script::SetProperty(rq, settings, "sdl_video_backend", backend ? backend : "unknown");
231 :
232 0 : Script::SetProperty(rq, settings, "sdl_display_count", SDL_GetNumVideoDisplays());
233 :
234 0 : Script::SetProperty(rq, settings, "sdl_cpu_count", SDL_GetCPUCount());
235 0 : Script::SetProperty(rq, settings, "sdl_system_ram", SDL_GetSystemRAM());
236 0 : }
237 :
238 0 : static void ReportFreeType(const ScriptRequest& rq, JS::HandleValue settings)
239 : {
240 : FT_Library FTLibrary;
241 0 : std::string FTSupport = "unsupported";
242 0 : if (!FT_Init_FreeType(&FTLibrary))
243 : {
244 : FT_Int major, minor, patch;
245 0 : FT_Library_Version(FTLibrary, &major, &minor, &patch);
246 0 : FT_Done_FreeType(FTLibrary);
247 0 : std::stringstream version;
248 0 : version << major << "." << minor << "." << patch;
249 0 : FTSupport = version.str();
250 : }
251 : else
252 : {
253 0 : FTSupport = "cantload";
254 : }
255 0 : Script::SetProperty(rq, settings, "freetype", FTSupport);
256 3 : }
257 :
|