1 // Copyright 2016-2021 Doug Moen
2 // Licensed under the Apache License, version 2.0
3 // See accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0
4
5 #include "version.h"
6 #include <libcurv/version.h>
7 extern "C" {
8 #ifndef _WIN32
9 #include <sys/utsname.h>
10 #endif
11 #include <stdlib.h>
12 }
13 #include <libcurv/viewer/glfw.h>
14
15 #define USE_X11 0
16 #if USE_X11
17 #include <X11/Xlib.h>
18 #include <GL/glx.h>
19 #endif
20
21 void
print_gpu(std::ostream & out)22 print_gpu(std::ostream& out)
23 {
24 // GPU information: see `glxinfo` on Linux, but I don't want hundreds of
25 // lines of gibberish. I want: GPU model, driver version, OpenGL version.
26 // If X11, then 'direct rendering':' from glxinfo.
27
28 static std::ostream* gout;
29
30 out.flush(); // In case of crash while querying GPU.
31
32 // This is a nice sanity test of Curv's ability to access the GPU.
33 // If this doesn't work, there's no need to debug anything deep in the
34 // Viewer code.
35
36 gout = &out;
37 glfwSetErrorCallback([](int err, const char* msg)->void {
38 *gout << "GPU: "<<msg<<"\n";
39 });
40 if(!glfwInit()) {
41 return;
42 }
43
44 glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
45 GLFWwindow* window = glfwCreateWindow(100, 100, "version", NULL, NULL);
46 if (window == nullptr) {
47 return;
48 }
49 glfwMakeContextCurrent(window);
50 if (!curv::viewer::opengl_init()) {
51 *gout << "GPU: can't load OpenGL library\n";
52 return;
53 }
54
55 const char* vendor = (const char*) glGetString(GL_VENDOR);
56 if (vendor == nullptr) vendor = "???";
57 const char* renderer = (const char*) glGetString(GL_RENDERER);
58 if (renderer == nullptr) renderer = "???";
59 const char* version = (const char*) glGetString(GL_VERSION);
60 if (version == nullptr) version = "???";
61
62 out << "GPU: " << vendor << ", " << renderer << "\n";
63 out << "OpenGL: " << version << "\n";
64 out.flush();
65
66 #if USE_X11
67 char* display_name = getenv("DISPLAY");
68 if (display_name != nullptr) {
69 // X11 specific information, from glxinfo
70 // To get correct information, I need to use the same display and ctx
71 // that GLFW is using. This doesn't work.
72 Display* display = XOpenDisplay(display_name);
73 if (display == nullptr)
74 return;
75 GLXContext ctx = 0;
76 out << "Direct Rendering: ";
77 if (glXIsDirect(display, ctx)) {
78 out << "Yes\n";
79 }
80 else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
81 out << "No (LIBGL_ALWAYS_INDIRECT set)\n";
82 }
83 else {
84 out << "No (If you want to find out why, try setting "
85 "LIBGL_DEBUG=verbose)\n";
86 }
87 XCloseDisplay(display);
88 }
89 #endif
90
91 // In principle, this should free resources and leave no storage leaks.
92 glfwDestroyWindow(window);
93 glfwTerminate();
94 }
95
96 void
print_os(std::ostream & out)97 print_os(std::ostream& out)
98 {
99 // TODO: print "OS" distro name and version.
100 // On Linux (os.sysname=="Linux"), use /etc/os-release,
101 // see <https://www.freedesktop.org/software/systemd/man/os-release.html>
102 // On macOS (os.sysname=="Darwin"), use
103 // /System/Library/CoreServices/SystemVersion.plist
104
105 #ifdef _WIN32
106 // TODO Get version on Windows, see also
107 // https://docs.microsoft.com/en-US/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
108 out << "Kernel: Windows\n";
109 #else
110 struct utsname os;
111 uname(&os);
112 out << "Kernel: " << os.sysname << " " << os.release
113 << " " << os.machine << "\n";
114 #endif
115 }
116
117 void
print_cpu(std::ostream &)118 print_cpu(std::ostream&)
119 {
120 // CPU information: see `lscpu` on Linux.
121
122 // TODO: cpu -- see `lscpu` on Linux. name, model, # of cores
123 // TODO: vm -- see `lscpu` on Linux
124 // TODO: The amount of RAM.
125 // see https://github.com/dylanaraps/neofetch
126 }
127
128 void
print_compiler(std::ostream & out)129 print_compiler(std::ostream& out)
130 {
131 #if defined __clang_version__
132 out << "Compiler: clang " << __clang_version__ << "\n";
133 #elif defined __GNUC__
134 out << "Compiler: gcc " << __VERSION__ << "\n";
135 #else
136 (void) out;
137 #endif
138 }
139
140 // Print version information useful for bug reports.
141 // Inspiration: openscad --info,
142 // and neofetch, which displays terse and readable system information:
143 // see <https://github.com/dylanaraps/neofetch>
144 void
print_version(std::ostream & out)145 print_version(std::ostream& out)
146 {
147 out << "Curv: " << CURV_VERSION << "\n";
148 print_compiler(out);
149 print_os(out);
150 print_cpu(out);
151 print_gpu(out); // Last info printed, due to crashiness.
152 }
153