]> git.sesse.net Git - nageru/blob - main.cpp
Fix an issue where the mixer lagging too much behind CEF would cause us to display...
[nageru] / main.cpp
1 extern "C" {
2 #include <libavformat/avformat.h>
3 }
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/mman.h>
8 #include <epoxy/gl.h>  // IWYU pragma: keep
9 #include <QApplication>
10 #include <QCoreApplication>
11 #include <QGL>
12 #include <QSize>
13 #include <QSurfaceFormat>
14 #include <string>
15
16 #ifdef HAVE_CEF
17 #include <cef_app.h>
18 #include <cef_browser.h>
19 #include <cef_client.h>
20 #include <cef_version.h>
21 #endif
22
23 #include "basic_stats.h"
24 #ifdef HAVE_CEF
25 #include "nageru_cef_app.h"
26 #endif
27 #include "context.h"
28 #include "flags.h"
29 #include "image_input.h"
30 #include "mainwindow.h"
31 #include "mixer.h"
32
33 #ifdef HAVE_CEF
34 CefRefPtr<NageruCefApp> cef_app;
35 #endif
36
37 int main(int argc, char *argv[])
38 {
39 #ifdef HAVE_CEF
40         // Let CEF have first priority on parsing the command line, because we might be
41         // launched as a CEF sub-process.
42         CefMainArgs main_args(argc, argv);
43         cef_app = CefRefPtr<NageruCefApp>(new NageruCefApp());
44         int err = CefExecuteProcess(main_args, cef_app.get(), nullptr);
45         if (err >= 0) {
46                 return err;
47         }
48
49         // CEF wants to use GLib for its main loop, which interferes with Qt's use of it.
50         // The alternative is trying to integrate CEF into Qt's main loop, but that requires
51         // fairly extensive cross-thread communication and that parts of CEF runs on Qt's UI
52         // thread.
53         setenv("QT_NO_GLIB", "1", 0);
54 #endif
55
56         parse_flags(PROGRAM_NAGERU, argc, argv);
57
58         if (global_flags.va_display.empty() ||
59             global_flags.va_display[0] != '/') {
60                 // We normally use EGL for zerocopy, but if we use VA against DRM
61                 // instead of against X11, we turn it off, and then don't need EGL.
62                 setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0);
63                 using_egl = true;
64         }
65         setlinebuf(stdout);
66         av_register_all();
67
68         QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
69
70         QSurfaceFormat fmt;
71         fmt.setDepthBufferSize(0);
72         fmt.setStencilBufferSize(0);
73         fmt.setProfile(QSurfaceFormat::CoreProfile);
74         fmt.setMajorVersion(3);
75         fmt.setMinorVersion(1);
76
77         // Turn off vsync, since Qt generally gives us at most frame rate
78         // (display frequency) / (number of QGLWidgets active).
79         fmt.setSwapInterval(0);
80
81         QSurfaceFormat::setDefaultFormat(fmt);
82
83         QGLFormat::setDefaultFormat(QGLFormat::fromSurfaceFormat(fmt));
84
85         QApplication app(argc, argv);
86         global_share_widget = new QGLWidget();
87         if (!global_share_widget->isValid()) {
88                 fprintf(stderr, "Failed to initialize OpenGL. Nageru needs at least OpenGL 3.1 to function properly.\n");
89                 exit(1);
90         }
91
92         MainWindow mainWindow;
93         mainWindow.resize(QSize(1500, 850));
94         mainWindow.show();
95
96         app.installEventFilter(&mainWindow);  // For white balance color picking.
97
98         // Even on an otherwise unloaded system, it would seem writing the recording
99         // to disk (potentially terabytes of data as time goes by) causes Nageru
100         // to be pushed out of RAM. If we have the right privileges, simply lock us
101         // into memory for better realtime behavior.
102         if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
103                 perror("mlockall()");
104                 fprintf(stderr, "Failed to lock Nageru into RAM. You probably want to\n");
105                 fprintf(stderr, "increase \"memlock\" for your user in limits.conf\n");
106                 fprintf(stderr, "for better realtime behavior.\n");
107                 uses_mlock = false;
108         } else {
109                 uses_mlock = true;
110         }
111
112         int rc = app.exec();
113         global_mixer->quit();
114         mainWindow.mixer_shutting_down();
115         delete global_mixer;
116         ImageInput::shutdown_updaters();
117         return rc;
118 }