source: subsurface/subsurface-desktop-main.cpp

Last change on this file was a748e7f, checked in by Dirk Hohndel <dirk@…>, 5 weeks ago

Unify float calulations: use double

Internal floating point (FP) calculations should be performed using double
unless there is a very good reason. This avoids headaches with conversions.
Indeed, the vast majority of FP calculations were already done using double.
This patch adapts most remaining calculations. Not converted where things
that were based on binary representations and variables which weren't used
anyway.

An analysis of all instances follows:

core/plannernotes.c, l.404:

This was a comparison between two floats. On the left side, first an integer
was cast to float then multiplied with and integer and divided by a constant
double. The right hand side was an integer cast to a float. Simply divide by
1000.0 first to convert to double and continue with calculations. On the right
hand side, remove the cast, because the integer will be implicitely cast to
double for comparison. This conversion actually emits less instructions,
because no conversion to double and back is performed.

core/planner.c, l.613:

Same analysis as previous case.

subsurface-desktop-main.cpp, l.155:

A local variable representing the version OpenGL version. Turn this into
integer logic. Not only does this avoid dreaded FP rounding issues, it also
works correctly for minor version > 10 (not that such a thing is to be
expected anytime soon).

abstractpreferenceswidget.[h/cpp]:

A widget where the position is described as a float. Turn into double.

desktop-widgets/divelogexportdialog.cpp, l.313:

total_weight is described as float. Use double arithmetics instead. This
instance fixes a truncation warning emitted by gcc.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1// SPDX-License-Identifier: GPL-2.0
2/* main.c */
3#include <locale.h>
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <time.h>
8
9#include "core/dive.h"
10#include "core/qt-gui.h"
11#include "core/subsurfacestartup.h"
12#include "desktop-widgets/mainwindow.h"
13#include "desktop-widgets/tab-widgets/maintab.h"
14#include "profile-widget/profilewidget2.h"
15#include "desktop-widgets/preferences/preferencesdialog.h"
16#include "desktop-widgets/diveplanner.h"
17#include "core/color.h"
18#include "core/qthelper.h"
19#include "core/downloadfromdcthread.h" // for fill_computer_list
20
21#include <QStringList>
22#include <QApplication>
23#include <QLoggingCategory>
24#include <QOpenGLContext>
25#include <QOffscreenSurface>
26#include <QOpenGLFunctions>
27#include <QQuickWindow>
28#include <git2.h>
29
30static bool filesOnCommandLine = false;
31static void validateGL();
32static void messageHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg);
33
34int main(int argc, char **argv)
35{
36        subsurface_console_init();
37        qInstallMessageHandler(messageHandler);
38        if (verbose) /* print the version if the Win32 console_init() code enabled verbose. */
39                print_version();
40
41        int i;
42        bool no_filenames = true;
43        QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
44        QApplication *application = new QApplication(argc, argv);
45        (void)application;
46        QStringList files;
47        QStringList importedFiles;
48        QStringList arguments = QCoreApplication::arguments();
49
50        const char *default_directory = system_default_directory();
51        const char *default_filename = system_default_filename();
52        subsurface_mkdir(default_directory);
53
54        for (i = 1; i < arguments.length(); i++) {
55                QString a = arguments.at(i);
56                if (a.isEmpty())
57                        continue;
58                if (a.at(0) == '-') {
59                        parse_argument(a.toLocal8Bit().data());
60                        continue;
61                }
62                if (imported) {
63                        importedFiles.push_back(a);
64                } else {
65                        no_filenames = false;
66                        files.push_back(a);
67                }
68        }
69        if (subsurface_user_is_root() && !force_root) {
70                printf("You are running Subsurface as root. This is not recommended.\n");
71                printf("If you insist to do so, run with option --allow_run_as_root.\n");
72                exit(0);
73        }
74        validateGL();
75#if !LIBGIT2_VER_MAJOR && LIBGIT2_VER_MINOR < 22
76        git_threads_init();
77#else
78        git_libgit2_init();
79#endif
80        /*
81         * Initialize the random number generator - not really secure as
82         * this is based only on current time, but it should not matter
83         * that much in our context. Moreover this is better than
84         * the constant numbers we used to get before.
85         */
86        qsrand(time(NULL));
87        setup_system_prefs();
88        copy_prefs(&default_prefs, &prefs);
89        fill_profile_color();
90        fill_computer_list();
91        parse_xml_init();
92        taglist_init_global();
93        init_ui();
94        if (no_filenames) {
95                if (prefs.default_file_behavior == LOCAL_DEFAULT_FILE) {
96                        QString defaultFile(prefs.default_filename);
97                        if (!defaultFile.isEmpty())
98                                files.push_back(QString(prefs.default_filename));
99                } else if (prefs.default_file_behavior == CLOUD_DEFAULT_FILE) {
100                        QString cloudURL;
101                        if (getCloudURL(cloudURL) == 0)
102                                files.push_back(cloudURL);
103                }
104        }
105        MainWindow *m = MainWindow::instance();
106        filesOnCommandLine = !files.isEmpty() || !importedFiles.isEmpty();
107        if (verbose && !files.isEmpty())
108                qDebug() << "loading dive data from" << files;
109        m->loadFiles(files);
110        if (verbose && !importedFiles.isEmpty())
111                qDebug() << "importing dive data from" << importedFiles;
112        m->importFiles(importedFiles);
113
114        if (verbose > 0)
115                print_files();
116        if (!quit)
117                run_ui();
118        exit_ui();
119        taglist_free(g_tag_list);
120        parse_xml_exit();
121        free((void *)default_directory);
122        free((void *)default_filename);
123        subsurface_console_exit();
124        free_prefs();
125        return 0;
126}
127
128bool haveFilesOnCommandLine()
129{
130        return filesOnCommandLine;
131}
132
133#define VALIDATE_GL_PREFIX  "validateGL(): "
134
135void validateGL()
136{
137        QString quickBackend = qgetenv("QT_QUICK_BACKEND");
138        /* an empty QT_QUICK_BACKEND env. variable means OpenGL (default).
139         * only validate OpenGL; for everything else print out and return.
140         * https://doc.qt.io/qt-5/qtquick-visualcanvas-adaptations.html
141         */
142        if (!quickBackend.isEmpty()) {
143                if (verbose) {
144                        qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "'QT_QUICK_BACKEND' is set to '%1'. "
145                                "Skipping validation.").arg(quickBackend).toUtf8().data();
146                }
147                return;
148        }
149        GLint verMajor = -1, verMinor;
150        const char *glError = NULL;
151        QOpenGLContext ctx;
152        QOffscreenSurface surface;
153        QOpenGLFunctions *func;
154        const char *verChar;
155
156        surface.setFormat(ctx.format());
157        surface.create();
158        if (!ctx.create()) {
159                glError = "Cannot create OpenGL context";
160                goto exit;
161        }
162        if (verbose)
163                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "created OpenGLContext.").toUtf8().data();
164        ctx.makeCurrent(&surface);
165        func = ctx.functions();
166        if (!func) {
167                glError = "Cannot obtain QOpenGLFunctions";
168                goto exit;
169        }
170        if (verbose)
171                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "obtained QOpenGLFunctions.").toUtf8().data();
172        // detect version for legacy profiles
173        verChar = (const char *)func->glGetString(GL_VERSION);
174        if (verChar) {
175                // detect GLES, show a warning and return early as we don't handle it's versioning
176                if (strstr(verChar, " ES ") != NULL) {
177                         qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "WARNING: Detected OpenGL ES!\n"
178                         "Attempting to run with the available profile!\n"
179                         "If this fails try manually setting the environment variable\n"
180                         "'QT_QUICK_BACKEND' with the value of 'software'\n"
181                         "before running Subsurface!\n").toUtf8().data();
182                         return;
183                }
184                int min, maj;
185                if (sscanf(verChar, "%d.%d", &maj, &min) == 2) {
186                        verMajor = (GLint)maj;
187                        verMinor = (GLint)min;
188                }
189        }
190        // attempt to detect version using the newer API
191        if (verMajor == -1) {
192                func->glGetIntegerv(GL_MAJOR_VERSION, &verMajor);
193                func->glGetIntegerv(GL_MINOR_VERSION, &verMinor);
194        }
195        if (verMajor == -1) {
196                glError = "Cannot detect OpenGL version";
197                goto exit;
198        }
199        if (verbose)
200                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "detected OpenGL version %1.%2.").arg(verMajor).arg(verMinor).toUtf8().data();
201        if (verMajor * 10 + verMinor < 21) { // set 2.1 as the minimal version
202                glError = "OpenGL 2.1 or later is required";
203                goto exit;
204        }
205
206exit:
207        ctx.makeCurrent(NULL);
208        surface.destroy();
209        if (glError) {
210#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0)
211                qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "ERROR: %1.\n"
212                        "Cannot automatically fallback to a software renderer!\n"
213                        "Set the environment variable 'QT_QUICK_BACKEND' with the value of 'software'\n"
214                        "before running Subsurface!\n").arg(glError).toUtf8().data();
215                exit(0);
216#else
217                qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "WARNING: %1. Using a software renderer!").arg(glError).toUtf8().data();
218                QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
219#endif
220        }
221}
222
223// install this message handler primarily so that the Windows build can log to files
224void messageHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg)
225{
226        Q_UNUSED(ctx);
227        QByteArray localMsg = msg.toLocal8Bit();
228        switch (type) {
229        case QtDebugMsg:
230                fprintf(stdout, "%s\n", localMsg.constData());
231                break;
232        case QtInfoMsg:
233                fprintf(stdout, "%s\n", localMsg.constData());
234                break;
235        case QtWarningMsg:
236                fprintf(stderr, "%s\n", localMsg.constData());
237                break;
238        case QtCriticalMsg:
239                fprintf(stderr, "%s\n", localMsg.constData());
240                break;
241        case QtFatalMsg:
242                fprintf(stderr, "%s\n", localMsg.constData());
243                abort();
244        }
245}
Note: See TracBrowser for help on using the repository browser.