Skip to content

Commit 9392f2c

Browse files
authored
Merge pull request #127 from cortex-command-community/gl-check-update
AbortLog Hardware Reporting
2 parents 537867f + 6e074d2 commit 9392f2c

File tree

4 files changed

+214
-15
lines changed

4 files changed

+214
-15
lines changed

Source/System/GLCheck.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,75 @@
11
#include "GLCheck.h"
22
#include "glad/gl.h"
33

4-
#include <cstdio>
5-
#include <cstdlib>
4+
#include <string>
5+
#include <sstream>
6+
#include "ConsoleMan.h"
7+
using namespace RTE;
68

79
void CheckOpenGLError(const char* stmt, const char* fname, int line) {
8-
GLenum err = glGetError();
9-
if (err != GL_NO_ERROR) {
10-
printf("OpenGL error %08x, at %s:%i - for %s\n", err, fname, line, stmt);
11-
abort();
10+
GLenum errorCode = glGetError();
11+
12+
if (errorCode != GL_NO_ERROR) {
13+
std::string fileString = fname;
14+
std::string error = "Unknown error";
15+
std::string description = "No description";
16+
17+
// Decode the error code
18+
switch (errorCode) {
19+
case GL_INVALID_ENUM: {
20+
error = "GL_INVALID_ENUM";
21+
description = "An unacceptable value has been specified for an enumerated argument.";
22+
break;
23+
}
24+
25+
case GL_INVALID_VALUE: {
26+
error = "GL_INVALID_VALUE";
27+
description = "A numeric argument is out of range.";
28+
break;
29+
}
30+
31+
case GL_INVALID_OPERATION: {
32+
error = "GL_INVALID_OPERATION";
33+
description = "The specified operation is not allowed in the current state.";
34+
break;
35+
}
36+
37+
case GL_STACK_OVERFLOW: {
38+
error = "GL_STACK_OVERFLOW";
39+
description = "This command would cause a stack overflow.";
40+
break;
41+
}
42+
43+
case GL_STACK_UNDERFLOW: {
44+
error = "GL_STACK_UNDERFLOW";
45+
description = "This command would cause a stack underflow.";
46+
break;
47+
}
48+
49+
case GL_OUT_OF_MEMORY: {
50+
error = "GL_OUT_OF_MEMORY";
51+
description = "There is not enough memory left to execute the command.";
52+
break;
53+
}
54+
55+
case GL_INVALID_FRAMEBUFFER_OPERATION: {
56+
error = "GL_INVALID_FRAMEBUFFER_OPERATION";
57+
description = "The object bound to FRAMEBUFFER_BINDING is not \"framebuffer complete\".";
58+
break;
59+
}
60+
61+
default: {
62+
error = "Unknown Error" + std::to_string(errorCode);
63+
description = "";
64+
}
65+
}
66+
67+
// Log the error
68+
std::stringstream errorMessage;
69+
errorMessage << "ERROR: An internal OpenGL call failed in "
70+
<< fileString.substr(fileString.find_last_of("\\/") + 1) << "(" << line << ")."
71+
<< "\nExpression:\n " << stmt
72+
<< "\nError description:\n " << error << "\n " << description << "\n";
73+
g_ConsoleMan.PrintString(errorMessage.str());
1274
}
1375
}

Source/System/GLCheck.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@
55
void CheckOpenGLError(const char* stmt, const char* fname, int line);
66

77
/// Debug macro to be used for all GL calls.
8-
#ifdef DEBUG
98
#define GL_CHECK(stmt) \
109
do { \
1110
stmt; \
1211
CheckOpenGLError(#stmt, __FILE__, __LINE__); \
1312
} while (0)
14-
#else
15-
#define GL_CHECK(stmt) stmt
16-
#endif

Source/System/RTEError.cpp

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@
2020
#include <utility>
2121
#include <vector>
2222

23+
#ifdef _MSC_VER
24+
#include <intrin.h>
25+
#elif defined(__linux__)
26+
#include <cpuid.h>
27+
#endif
28+
29+
#ifdef __linux__
30+
#include <sys/utsname.h>
31+
#include <fstream>
32+
#include <filesystem>
33+
#elif defined(__APPLE__) && defined(__MACH__)
34+
#include <sys/sysctl.h>
35+
#endif
36+
2337
using namespace RTE;
2438

2539
bool RTEError::s_CurrentlyAborting = false;
@@ -326,6 +340,8 @@ void RTEError::AbortFunc(const std::string& description, const std::source_locat
326340

327341
g_ConsoleMan.PrintString(abortMessage);
328342

343+
DumpHardwareInfo();
344+
329345
std::string callstack = "";
330346

331347
#ifdef _WIN32
@@ -386,8 +402,8 @@ void RTEError::AssertFunc(const std::string& description, const std::source_loca
386402

387403
if (!s_IgnoreAllAsserts) {
388404
std::string assertMessage =
389-
"Assertion in file '" + fileName + "', line " + lineNum + ",\nin function '" + funcName + "'\nbecause:\n\n" + description + "\n\n"
390-
"You may choose to ignore this and crash immediately\nor at some unexpected point later on.\n\nProceed at your own risk!";
405+
"Assertion in file '" + fileName + "', line " + lineNum + ",\nin function '" + funcName + "'\nbecause:\n\n" + description + "\n\n" +
406+
"You may choose to ignore this and crash immediately\nor at some unexpected point later on.\n\nProceed at your own risk!";
391407

392408
if (ShowAssertMessageBox(assertMessage)) {
393409
AbortFunc(description, srcLocation);
@@ -404,6 +420,121 @@ void RTEError::AssertFunc(const std::string& description, const std::source_loca
404420
}
405421
}
406422

423+
void RTEError::DumpHardwareInfo() {
424+
std::string glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
425+
std::string glVendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
426+
std::string glRenderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
427+
std::string hwInfo = "GL Version: " + glVersion + "\n" +
428+
"GL Vendor: " + glVendor + "\n" +
429+
"GL Renderer: " + glRenderer + "\n";
430+
431+
#if defined(_MSC_VER) || defined(__linux__)
432+
int vendorRegs[4] = {0};
433+
#ifdef _MSC_VER
434+
__cpuid(vendorRegs, 0);
435+
#else
436+
__cpuid(0, vendorRegs[0], vendorRegs[1], vendorRegs[2], vendorRegs[3]);
437+
#endif
438+
439+
std::string cpuVendor(reinterpret_cast<const char*>(&vendorRegs[1]), 4);
440+
cpuVendor += std::string(reinterpret_cast<const char*>(&vendorRegs[3]), 4);
441+
cpuVendor += std::string(reinterpret_cast<const char*>(&vendorRegs[2]), 4);
442+
443+
hwInfo += "CPU Manufacturer ID: " + cpuVendor + "\n";
444+
445+
std::string cpuModel;
446+
int modelRegs[12];
447+
#ifdef _MSC_VER
448+
__cpuid(modelRegs, 0x80000000);
449+
#else
450+
__cpuid(0x80000000, modelRegs[0], modelRegs[1], modelRegs[2], modelRegs[3]);
451+
#endif
452+
if (modelRegs[0] >= 0x80000004) {
453+
for (size_t i = 0; i <= 2; ++i) {
454+
#ifdef _MSC_VER
455+
__cpuid(&modelRegs[0] + i * 4, i + 0x80000002);
456+
#else
457+
__cpuid(i + 0x80000002, modelRegs[0 + i * 4], modelRegs[1 + i * 4], modelRegs[2 + i * 4], modelRegs[3 + i * 4]);
458+
#endif
459+
}
460+
for (size_t i = 0; i < 12; ++i) {
461+
cpuModel += std::string(reinterpret_cast<const char*>(&modelRegs[i]), 4);
462+
}
463+
464+
hwInfo += "CPU Model: " + cpuModel + "\n";
465+
}
466+
#elif defined(__APPLE__) && defined(__MACH__)
467+
char vendor[1024];
468+
size_t vendorSize = sizeof(vendor);
469+
int error = sysctlbyname("machdep.cpu.vendor", &vendor, &vendorSize, nullptr, 0);
470+
if (!error) {
471+
hwInfo += "CPU Vendor: " + std::string(vendor) + "\n";
472+
}
473+
char brand[1024];
474+
size_t brandSize = sizeof(brand);
475+
error = sysctlbyname("machdep.cpu.brand_string", &brand, &brandSize, nullptr, 0);
476+
if (!error) {
477+
hwInfo += "CPU Model: " + std::string(brand) + "\n";
478+
}
479+
#endif
480+
481+
g_ConsoleMan.PrintString(hwInfo);
482+
483+
#ifdef __unix__
484+
struct utsname unameData;
485+
if (uname(&unameData) == 0) {
486+
std::string osInfo = "uname: " + std::string(unameData.sysname) + " " + std::string(unameData.release) + " " + std::string(unameData.version);
487+
g_ConsoleMan.PrintString(osInfo);
488+
}
489+
#endif
490+
491+
#ifdef _MSC_VER
492+
g_ConsoleMan.PrintString("OS: Windows");
493+
#endif
494+
495+
#ifdef __linux__
496+
// Read distribution info from /etc/os-release
497+
if (std::filesystem::exists("/etc/os-release")) {
498+
std::ifstream osReleaseFile("/etc/os-release");
499+
if (osReleaseFile.is_open()) {
500+
std::string line;
501+
while (std::getline(osReleaseFile, line)) {
502+
if (line.find("PRETTY_NAME") != std::string::npos) {
503+
g_ConsoleMan.PrintString("OS: " + line.substr(line.find_first_of('"') + 1, line.find_last_of('"') - line.find_first_of('"') - 1));
504+
break;
505+
}
506+
}
507+
osReleaseFile.close();
508+
}
509+
} else {
510+
g_ConsoleMan.PrintString("OS: Unknown Linux (/etc/os-release not found)");
511+
}
512+
#endif
513+
514+
#if defined(__APPLE__) && defined(__MACH__)
515+
char osType[1024];
516+
size_t osTypeSize = sizeof(osType);
517+
error = sysctlbyname("kern.ostype", &osType, &osTypeSize, nullptr, 0);
518+
if (!error) {
519+
g_ConsoleMan.PrintString("OS Type: " + std::string(osType));
520+
}
521+
522+
char osRelease[1024];
523+
size_t osReleaseSize = sizeof(osRelease);
524+
error = sysctlbyname("kern.osrelease", &osRelease, &osReleaseSize, nullptr, 0);
525+
if (!error) {
526+
g_ConsoleMan.PrintString("OS Release: " + std::string(osRelease));
527+
}
528+
529+
char osVersion[1024];
530+
size_t osVersionSize = sizeof(osVersion);
531+
error = sysctlbyname("kern.osversion", &osVersion, &osVersionSize, nullptr, 0);
532+
if (!error) {
533+
g_ConsoleMan.PrintString("OS Version: " + std::string(osVersion));
534+
}
535+
#endif
536+
}
537+
407538
bool RTEError::DumpAbortScreen() {
408539
int success = -1;
409540
if (glReadPixels != nullptr) {
@@ -442,9 +573,10 @@ bool RTEError::DumpAbortSave() {
442573

443574
void RTEError::FormatFunctionSignature(std::string& symbolName) {
444575
// TODO: Expand this with more dumb signatures, or make something that makes more sense.
445-
static const std::array<std::pair<std::regex, std::string>, 3> stlSigs{{{std::regex("( >)"), ">"},
446-
{std::regex("(std::basic_string<char,std::char_traits<char>,std::allocator<char>>)"), "std::string"},
447-
{std::regex("(class ?std::basic_string<char,struct ?std::char_traits<char>,class ?std::allocator<char>>)"), "std::string"}}};
576+
static const std::array<std::pair<std::regex, std::string>, 3> stlSigs{
577+
{{std::regex("( >)"), ">"},
578+
{std::regex("(std::basic_string<char,std::char_traits<char>,std::allocator<char>>)"), "std::string"},
579+
{std::regex("(class ?std::basic_string<char,struct ?std::char_traits<char>,class ?std::allocator<char>>)"), "std::string"}}};
448580
for (const auto& [fullSig, simpleSig]: stlSigs) {
449581
symbolName = std::regex_replace(symbolName, fullSig, simpleSig);
450582
}

Source/System/RTEError.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ namespace RTE {
6666
/// @return Whether to abort, or ignore the assert and continue execution.
6767
static bool ShowAssertMessageBox(const std::string& message);
6868

69+
/// Prints details on the user hardware to the abort log.
70+
/// @remark
71+
/// Included details:
72+
/// OpenGL version string, OpenGL GPU vendor string, OpenGL Renderer string.
73+
/// CPU vendor and brand string (as reported by cpuid on windows and linux or sysctl on macos).
74+
/// linux: uname sysname, release, version.
75+
/// macos: sysctl kern.osrelease, kern.ostype, kern.osversion.
76+
static void DumpHardwareInfo();
77+
6978
/// Saves the current frame to a file.
7079
/// @return Whether the file was saved successfully.@return
7180
static bool DumpAbortScreen();

0 commit comments

Comments
 (0)