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 "ps/Util.h"
21 :
22 : #include "graphics/GameView.h"
23 : #include "lib/allocators/shared_ptr.h"
24 : #include "lib/posix/posix_utsname.h"
25 : #include "lib/sysdep/cpu.h"
26 : #include "lib/sysdep/os_cpu.h"
27 : #include "lib/sysdep/smbios.h"
28 : #include "lib/sysdep/sysdep.h" // sys_OpenFile
29 : #include "lib/tex/tex.h"
30 : #include "lib/timer.h"
31 : #include "ps/CLogger.h"
32 : #include "ps/Filesystem.h"
33 : #include "ps/GameSetup/Config.h"
34 : #include "ps/GameSetup/GameSetup.h"
35 : #include "ps/Pyrogenesis.h"
36 : #include "ps/VideoMode.h"
37 : #include "renderer/backend/IDevice.h"
38 :
39 : #if CONFIG2_AUDIO
40 : #include "soundmanager/SoundManager.h"
41 : #endif
42 :
43 : #include <iomanip>
44 : #include <sstream>
45 :
46 0 : void WriteSystemInfo()
47 : {
48 0 : TIMER(L"write_sys_info");
49 : struct utsname un;
50 0 : uname(&un);
51 :
52 0 : OsPath pathname = psLogDir()/"system_info.txt";
53 0 : FILE* f = sys_OpenFile(pathname, "w");
54 0 : if(!f)
55 0 : return;
56 :
57 : // current timestamp (redundant WRT OS timestamp, but that is not
58 : // visible when people are posting this file's contents online)
59 : {
60 0 : wchar_t timestampBuf[100] = {'\0'};
61 : time_t seconds;
62 0 : time(&seconds);
63 0 : struct tm* t = gmtime(&seconds);
64 0 : const size_t charsWritten = wcsftime(timestampBuf, ARRAY_SIZE(timestampBuf), L"(generated %Y-%m-%d %H:%M:%S UTC)", t);
65 0 : ENSURE(charsWritten != 0);
66 0 : fprintf(f, "%ls\n\n", timestampBuf);
67 : }
68 :
69 : // OS
70 0 : fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version);
71 :
72 : // CPU
73 0 : fprintf(f, "CPU : %s, %s", un.machine, cpu_IdentifierString());
74 0 : double cpuClock = os_cpu_ClockFrequency(); // query OS (may fail)
75 : #if ARCH_X86_X64
76 0 : if(cpuClock <= 0.0)
77 0 : cpuClock = x86_x64::ClockFrequency(); // measure (takes a few ms)
78 : #endif
79 0 : if(cpuClock > 0.0)
80 : {
81 0 : if(cpuClock < 1e9)
82 0 : fprintf(f, ", %.2f MHz\n", cpuClock*1e-6);
83 : else
84 0 : fprintf(f, ", %.2f GHz\n", cpuClock*1e-9);
85 : }
86 : else
87 0 : fprintf(f, "\n");
88 :
89 : // memory
90 0 : fprintf(f, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable());
91 :
92 : // graphics
93 0 : fprintf(f, "Video Card : %s\n", g_VideoMode.GetBackendDevice()->GetName().c_str());
94 0 : fprintf(f, "Video Driver : %s\n", g_VideoMode.GetBackendDevice()->GetDriverInformation().c_str());
95 0 : fprintf(f, "Video Mode : %dx%d:%d\n", g_VideoMode.GetXRes(), g_VideoMode.GetYRes(), g_VideoMode.GetBPP());
96 :
97 : #if CONFIG2_AUDIO
98 0 : if (g_SoundManager)
99 : {
100 0 : fprintf(f, "Sound Card : %s\n", g_SoundManager->GetSoundCardNames().c_str());
101 0 : fprintf(f, "Sound Drivers : %s\n", g_SoundManager->GetOpenALVersion().c_str());
102 : }
103 0 : else if(g_DisableAudio)
104 0 : fprintf(f, "Sound : Game was ran without audio\n");
105 : else
106 0 : fprintf(f, "Sound : No audio device was found\n");
107 : #else
108 : fprintf(f, "Sound : Game was compiled without audio\n");
109 : #endif
110 :
111 : // OpenGL extensions (write them last, since it's a lot of text)
112 0 : fprintf(f, "\nBackend Extensions:\n");
113 0 : if (g_VideoMode.GetBackendDevice()->GetExtensions().empty())
114 0 : fprintf(f, "{unknown}\n");
115 : else
116 0 : for (const std::string& extension : g_VideoMode.GetBackendDevice()->GetExtensions())
117 0 : fprintf(f, "%s\n", extension.c_str());
118 :
119 : // System Management BIOS (even more text than OpenGL extensions)
120 0 : std::string smbios = SMBIOS::StringizeStructures(SMBIOS::GetStructures());
121 0 : fprintf(f, "\nSMBIOS: \n%s\n", smbios.c_str());
122 :
123 0 : fclose(f);
124 0 : f = 0;
125 :
126 0 : debug_printf("FILES| Hardware details written to '%s'\n", pathname.string8().c_str());
127 : }
128 :
129 :
130 : // not thread-safe!
131 0 : static const wchar_t* HardcodedErrorString(int err)
132 : {
133 : static wchar_t description[200];
134 0 : StatusDescription((Status)err, description, ARRAY_SIZE(description));
135 0 : return description;
136 : }
137 :
138 : // not thread-safe!
139 0 : const wchar_t* ErrorString(int err)
140 : {
141 : // language file not available (yet)
142 0 : return HardcodedErrorString(err);
143 :
144 : // TODO: load from language file
145 : }
146 :
147 0 : CStr GetStatusAsString(Status status)
148 : {
149 0 : return utf8_from_wstring(ErrorString(status));
150 : }
151 :
152 : // write the specified texture to disk.
153 : // note: <t> cannot be made const because the image may have to be
154 : // transformed to write it out in the format determined by <fn>'s extension.
155 0 : Status tex_write(Tex* t, const VfsPath& filename)
156 : {
157 : DynArray da;
158 0 : RETURN_STATUS_IF_ERR(t->encode(filename.Extension(), &da));
159 :
160 : // write to disk
161 0 : Status ret = INFO::OK;
162 : {
163 0 : std::shared_ptr<u8> file = DummySharedPtr(da.base);
164 0 : const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos);
165 0 : if(bytes_written > 0)
166 0 : ENSURE(bytes_written == (ssize_t)da.pos);
167 : else
168 0 : ret = (Status)bytes_written;
169 : }
170 :
171 0 : ignore_result(da_free(&da));
172 0 : return ret;
173 : }
174 :
175 : /**
176 : * Return an unused directory, based on date and index (for example 2016-02-09_0001)
177 : */
178 0 : OsPath createDateIndexSubdirectory(const OsPath& parentDir)
179 : {
180 0 : const std::time_t timestamp = std::time(nullptr);
181 0 : const struct std::tm* now = std::localtime(×tamp);
182 :
183 : // Two processes executing this simultaneously might attempt to create the same directory.
184 0 : int tries = 0;
185 0 : const int maxTries = 10;
186 :
187 0 : int i = 0;
188 0 : OsPath path;
189 : char directory[256];
190 :
191 0 : do
192 : {
193 0 : sprintf(directory, "%04d-%02d-%02d_%04d", now->tm_year+1900, now->tm_mon+1, now->tm_mday, ++i);
194 0 : path = parentDir / CStr(directory);
195 :
196 0 : if (DirectoryExists(path) || FileExists(path))
197 0 : continue;
198 :
199 0 : if (CreateDirectories(path, 0700, ++tries > maxTries) == INFO::OK)
200 0 : break;
201 :
202 0 : } while(tries <= maxTries);
203 :
204 0 : return path;
205 : }
206 :
207 0 : std::string Hexify(const std::string& s)
208 : {
209 0 : std::stringstream str;
210 0 : str << std::hex;
211 0 : for (const char& c : s)
212 0 : str << std::setfill('0') << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
213 0 : return str.str();
214 : }
215 :
216 495 : std::string Hexify(const u8* s, size_t length)
217 : {
218 990 : std::stringstream str;
219 495 : str << std::hex;
220 5591 : for (size_t i = 0; i < length; ++i)
221 5096 : str << std::setfill('0') << std::setw(2) << static_cast<int>(s[i]);
222 990 : return str.str();
223 3 : }
|