1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
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"
40 #include "soundmanager/SoundManager.h"
46 void WriteSystemInfo()
48 TIMER(L
"write_sys_info");
52 OsPath pathname
= psLogDir()/"system_info.txt";
53 FILE* f
= sys_OpenFile(pathname
, "w");
57 // current timestamp (redundant WRT OS timestamp, but that is not
58 // visible when people are posting this file's contents online)
60 wchar_t timestampBuf
[100] = {'\0'};
63 struct tm
* t
= gmtime(&seconds
);
64 const size_t charsWritten
= wcsftime(timestampBuf
, ARRAY_SIZE(timestampBuf
), L
"(generated %Y-%m-%d %H:%M:%S UTC)", t
);
65 ENSURE(charsWritten
!= 0);
66 fprintf(f
, "%ls\n\n", timestampBuf
);
70 fprintf(f
, "OS : %s %s (%s)\n", un
.sysname
, un
.release
, un
.version
);
73 fprintf(f
, "CPU : %s, %s", un
.machine
, cpu_IdentifierString());
74 double cpuClock
= os_cpu_ClockFrequency(); // query OS (may fail)
77 cpuClock
= x86_x64::ClockFrequency(); // measure (takes a few ms)
82 fprintf(f
, ", %.2f MHz\n", cpuClock
*1e-6);
84 fprintf(f
, ", %.2f GHz\n", cpuClock
*1e-9);
90 fprintf(f
, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable());
93 fprintf(f
, "Video Card : %s\n", g_VideoMode
.GetBackendDevice()->GetName().c_str());
94 fprintf(f
, "Video Driver : %s\n", g_VideoMode
.GetBackendDevice()->GetDriverInformation().c_str());
95 fprintf(f
, "Video Mode : %dx%d:%d\n", g_VideoMode
.GetXRes(), g_VideoMode
.GetYRes(), g_VideoMode
.GetBPP());
100 fprintf(f
, "Sound Card : %s\n", g_SoundManager
->GetSoundCardNames().c_str());
101 fprintf(f
, "Sound Drivers : %s\n", g_SoundManager
->GetOpenALVersion().c_str());
103 else if(g_DisableAudio
)
104 fprintf(f
, "Sound : Game was ran without audio\n");
106 fprintf(f
, "Sound : No audio device was found\n");
108 fprintf(f
, "Sound : Game was compiled without audio\n");
111 // OpenGL extensions (write them last, since it's a lot of text)
112 fprintf(f
, "\nBackend Extensions:\n");
113 if (g_VideoMode
.GetBackendDevice()->GetExtensions().empty())
114 fprintf(f
, "{unknown}\n");
116 for (const std::string
& extension
: g_VideoMode
.GetBackendDevice()->GetExtensions())
117 fprintf(f
, "%s\n", extension
.c_str());
119 // System Management BIOS (even more text than OpenGL extensions)
120 std::string smbios
= SMBIOS::StringizeStructures(SMBIOS::GetStructures());
121 fprintf(f
, "\nSMBIOS: \n%s\n", smbios
.c_str());
126 debug_printf("FILES| Hardware details written to '%s'\n", pathname
.string8().c_str());
131 static const wchar_t* HardcodedErrorString(int err
)
133 static wchar_t description
[200];
134 StatusDescription((Status
)err
, description
, ARRAY_SIZE(description
));
139 const wchar_t* ErrorString(int err
)
141 // language file not available (yet)
142 return HardcodedErrorString(err
);
144 // TODO: load from language file
147 CStr
GetStatusAsString(Status status
)
149 return utf8_from_wstring(ErrorString(status
));
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 Status
tex_write(Tex
* t
, const VfsPath
& filename
)
158 RETURN_STATUS_IF_ERR(t
->encode(filename
.Extension(), &da
));
161 Status ret
= INFO::OK
;
163 std::shared_ptr
<u8
> file
= DummySharedPtr(da
.base
);
164 const ssize_t bytes_written
= g_VFS
->CreateFile(filename
, file
, da
.pos
);
165 if(bytes_written
> 0)
166 ENSURE(bytes_written
== (ssize_t
)da
.pos
);
168 ret
= (Status
)bytes_written
;
171 ignore_result(da_free(&da
));
176 * Return an unused directory, based on date and index (for example 2016-02-09_0001)
178 OsPath
createDateIndexSubdirectory(const OsPath
& parentDir
)
180 const std::time_t timestamp
= std::time(nullptr);
181 const struct std::tm
* now
= std::localtime(×tamp
);
183 // Two processes executing this simultaneously might attempt to create the same directory.
185 const int maxTries
= 10;
193 sprintf(directory
, "%04d-%02d-%02d_%04d", now
->tm_year
+1900, now
->tm_mon
+1, now
->tm_mday
, ++i
);
194 path
= parentDir
/ CStr(directory
);
196 if (DirectoryExists(path
) || FileExists(path
))
199 if (CreateDirectories(path
, 0700, ++tries
> maxTries
) == INFO::OK
)
202 } while(tries
<= maxTries
);
207 std::string
Hexify(const std::string
& s
)
209 std::stringstream str
;
211 for (const char& c
: s
)
212 str
<< std::setfill('0') << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c
));
216 std::string
Hexify(const u8
* s
, size_t length
)
218 std::stringstream str
;
220 for (size_t i
= 0; i
< length
; ++i
)
221 str
<< std::setfill('0') << std::setw(2) << static_cast<int>(s
[i
]);