878 lines · 33.4 KB · C++
RawDownload
////  main.cpp//  interface/src////  Copyright 2013 High Fidelity, Inc.//  Copyright 2022 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <QCommandLineParser>#include <QtCore/QProcess>#include <QDebug>#include <QDir>#include <QFileInfo>#include <QLocalSocket>#include <QLocalServer>#include <QSharedMemory>#include <QTranslator>#include <QStandardPaths> #include <BuildInfo.h>#include <SandboxUtils.h>#include <SharedUtil.h>#include <NetworkAccessManager.h>#include <gl/GLHelpers.h>#include <iostream>#include <plugins/InputPlugin.h>#include <plugins/PluginManager.h>#include <plugins/DisplayPlugin.h>#include <plugins/CodecPlugin.h>#include <shared/GlobalAppProperties.h> #include "AddressManager.h"#include "Application.h"#include "crash-handler/CrashHandler.h"#include "InterfaceLogging.h"#include "UserActivityLogger.h"#include "MainWindow.h"#include "Profile.h"#include "LogHandler.h"#include "RunningMarker.h" #ifdef Q_OS_WIN#include <Windows.h>extern "C" {    typedef int(__stdcall* CHECKMINSPECPROC)();}#endif int main(int argc, const char* argv[]) {#ifdef Q_OS_MAC    auto format = getDefaultOpenGLSurfaceFormat();    // Deal with some weirdness in the chromium context sharing on Mac.    // The primary share context needs to be 3.2, so that the Chromium will    // succeed in it's creation of it's command stub contexts.    format.setVersion(3, 2);    // This appears to resolve the issues with corrupted fonts on OSX.  No    // idea why.    qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true");    // https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg    QSurfaceFormat::setDefaultFormat(format);#endif     // You can force a specific graphics API with the --graphicsAPI option.  By default we will pick the best available based on the platform.    // Some systems may fallback to a lower API than requested based on what is supported.    std::string apiString;    for (int i = 1; i < argc; ++i) {        if (std::string(argv[i]) == "--graphicsAPI" && i + 1 < argc) {            apiString = argv[i + 1];            break;        }    }    if (!apiString.empty()) {        if (apiString == "gl45") {            hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45);        } else if (apiString == "gl41") {            hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41);        } else if (apiString == "gles32") {            hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32);        } else {            qWarning() << "Unknown graphics API specified, defaulting to GL4.5:" << QString::fromStdString(apiString);            hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45);        }    } else {#ifdef Q_OS_MAC        hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41);#elif defined(Q_OS_ANDROID) || (defined(Q_OS_LINUX) && defined(__aarch64__))        // Use GLES on Android and aarch64 Linux        hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32);#else        hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45);#endif    } #ifdef Q_OS_WIN    // Check the minimum GL version as early as possible    {        uint16_t available = gl::getAvailableVersion();        uint16_t required = gl::getRequiredVersion();        if (gl::getAvailableVersion() < gl::getRequiredVersion()) {            int availMajor = GL_GET_MAJOR_VERSION(available);            int availMinor = GL_GET_MINOR_VERSION(available);            int reqMajor = GL_GET_MAJOR_VERSION(required);            int reqMinor = GL_GET_MINOR_VERSION(required);            std::string message = "Interface requires OpenGL " + std::to_string(reqMajor) + "." + std::to_string(reqMinor) + " or higher. Available: " + std::to_string(availMajor) + "." + std::to_string(availMinor);            MessageBoxA(nullptr, message.c_str(), "Unsupported", MB_OK);            // GL version logging is currently disabled.  Version checking needs to happen before Application creation, but then the AccountManager + UserActivityLogger aren't set up yet.    #if 0            auto accountManager = DependencyManager::get<AccountManager>();            if (accountManager->isLoggedIn()) {                UserActivityLogger::getInstance().insufficientGLVersion(glData);            } else {                QObject::connect(accountManager.data(), &AccountManager::loginComplete, [glData](){                    static bool loggedInsufficientGL = false;                    if (!loggedInsufficientGL) {                        UserActivityLogger::getInstance().insufficientGLVersion(glData);                        loggedInsufficientGL = true;                    }                });            }    #endif            return -1;        }    }#endif     // Force-disable subpixel antialiasing on QML distance-field text.    // An existing override for QSG_DISTANCEFIELD_ANTIALIASING will be respected, and this    // variable will change nothing if QML_DISABLE_DISTANCEFIELD is set.    // Qt doesn't seem to have any public API for changing this besides the environment variable.    // See qtdeclarative/src/quick/scenegraph/qsgdefaultcontext.cpp    if (        auto aa = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING");        aa.isNull() || aa.isEmpty()    ) {        qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray");    }     // Setup QCoreApplication settings, install log message handler    setupHifiApplication(BuildInfo::INTERFACE_NAME);     // Journald by default in user applications is probably a bit too modern still.    LogHandler::getInstance().setShouldUseJournald(false);     std::vector<const char*> argvExtended(&argv[0], &argv[argc]);#ifdef Q_OS_ANDROID    argvExtended.push_back("--suppress-settings-reset");#endif    int argcExtended = (int)argvExtended.size();     QElapsedTimer startupTime;    startupTime.start();     QCommandLineParser parser;    parser.setApplicationDescription("Overte -- A free/libre and open-source virtual worlds client");    QCommandLineOption helpOption = parser.addHelpOption();    QCommandLineOption versionOption = parser.addVersionOption();     QCommandLineOption urlOption(        "url",        "Start at specified URL location.",        "string"    );    QCommandLineOption protocolVersionOption(        "protocolVersion",        "Writes the protocol version base64 signature to a file",        "path"    );    QCommandLineOption noUpdaterOption(        "no-updater",        "Do not show auto-updater."    );    QCommandLineOption checkMinSpecOption(        "checkMinSpec",        "Check if machine meets minimum specifications. The program will run if check passes."    );    QCommandLineOption runServerOption(        "runServer",        "Run the server."    );    QCommandLineOption listenPortOption(        "listenPort",        "Port to listen on.",        "port_number"    );    QCommandLineOption serverContentPathOption(        "serverContentPath",        "Path to find server content.", // What content??        "path"    );    QCommandLineOption overrideAppLocalDataPathOption(        "cache",        "Set test cache.",        "dir"    );    QCommandLineOption scriptsOption(        "scripts",        "Set path for defaultScripts. These are probably scripts that run automatically. This parameter does not seem to work.",        "dir"    );    QCommandLineOption allowMultipleInstancesOption(        "allowMultipleInstances",        "Allow multiple instances to run."    );    QCommandLineOption displaysOption(        "display",        "Preferred display plugin. Valid options include \"Desktop\", \"OpenXR\", and \"OpenVR (Vive)\". If \"Desktop\" is specified, all VR plugins are disabled.",        "displays"    );    QCommandLineOption disableDisplaysOption(        "disableDisplayPlugins",        "Display plugins to disable, separated by commas. Valid options include \"OpenXR\" and \"OpenVR (Vive)\".",        "string"    );    QCommandLineOption disableInputsOption(        "disableInputPlugins",        "Input plugins to disable, separated by commas. Valid options include \"SDL2\" (used only for gamepads), \"OpenXR\", and \"OpenVR (Vive)\".",        "string"    );    QCommandLineOption suppressSettingsResetOption(        "suppress-settings-reset",        "Suppress the prompt to reset interface settings."    );    QCommandLineOption oculusStoreOption(        "oculus-store",        "Let the Oculus plugin know if interface was run from the Oculus Store."    );    QCommandLineOption standaloneOption(        "standalone",        "Emulate a standalone device."    );    QCommandLineOption disableWatchdogOption(        "disableWatchdog",        "Disable the watchdog thread. The interface will crash on deadlocks."    );    QCommandLineOption systemCursorOption(        "system-cursor",        "Use the default system cursor."    );    QCommandLineOption concurrentDownloadsOption(        "concurrent-downloads",        "Maximum concurrent resource downloads. Default is 16, except for Android where it is 4.",        "integer"    );    QCommandLineOption avatarURLOption(        "avatarURL",        "Override the avatar U.R.L.",        "url"    );    QCommandLineOption replaceAvatarURLOption(        "replaceAvatarURL",        "Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.",        "url"    );    QCommandLineOption setBookmarkOption(        "setBookmark",        "Set bookmark as key=value pair. Including the '=' symbol in either string is unsupported.",        "string"    );    QCommandLineOption forceCrashReportingOption(        "forceCrashReporting",        "Force crash reporting to initialize."    );    // The documented "--disable-lod" does not seem to exist.    // Below are undocumented.    QCommandLineOption noLauncherOption(       "no-launcher",       "Supposedly does something for the server, unrelated to the application launcher. The feature may never have been implemented."    );    QCommandLineOption overrideScriptsPathOption(       "overrideScriptsPath",       "Specifies path to default directory where the application will look for scripts to load.",       "string"    );    QCommandLineOption defaultScriptsOverrideOption(       "defaultScriptsOverride",       "Override default script to run automatically on start. Default is \"defaultsScripts.js\".",       "string"    );    QCommandLineOption responseTokensOption(       "tokens",       "Set response tokens <json>.",       "json"    );    QCommandLineOption displayNameOption(       "displayName",       "Set user display name <string>.",       "string"    );    QCommandLineOption noLoginOption(       "no-login-suggestion",       "Do not show log-in dialogue."    );    QCommandLineOption traceFileOption(       "traceFile",       "Writes a trace to a file in the documents folder. Only works if \"--traceDuration\" is specified.",       "path"    );    QCommandLineOption traceDurationOption(       "traceDuration",       "Automatically quit interface after duration. Only works if \"--traceFile\" is specified.",       "seconds"    );    QCommandLineOption clockSkewOption(       "clockSkew",       "Forces client instance's clock to skew for demonstration purposes.",       "integer"    ); // This should probably be removed.    QCommandLineOption testScriptOption(       "testScript",       "Undocumented. Accepts parameter as U.R.L.",       "string"    );    QCommandLineOption testResultsLocationOption(       "testResultsLocation",       "Undocumented",       "path"    );    QCommandLineOption quitWhenFinishedOption(       "quitWhenFinished",       "Only works if \"--testScript\" is provided."    ); // Should probably also be made to work on testResultsLocationOption.    QCommandLineOption fastHeartbeatOption(       "fast-heartbeat",       "Change stats polling interval from 10000ms to 1000ms."    );    QCommandLineOption logOption(        "logOptions",        "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald",        "options"    );    QCommandLineOption getPluginsOption(        "getPlugins",        "Print out a list of plugins in JSON"    );    QCommandLineOption abortAfterStartupOption(        "abortAfterStartup",        "Debug option. Aborts right after startup."    );    QCommandLineOption abortAfterInitOption(        "abortAfterInit",        "Debug option. Aborts after initialization, right before the program starts running the event loop."    );    QCommandLineOption getProtocolVersionHashOption(        "getProtocolVersionHash",        "Debug option. Returns the network protocol version MD5 hash."    );    QCommandLineOption getProtocolVersionDataOption(        "getProtocolVersionData",        "Debug option. Returns the network protocol detailed data in JSON."    );    QCommandLineOption useExperimentalXROption(        "useExperimentalXR",        "Legacy alias of \"--display=OpenXR\"."    );    QCommandLineOption xrNoHandTrackingOption(        "xrNoHandTracking",        "Debug option. Disables OpenXR hand tracking, even if it's supported."    );    QCommandLineOption xrNoBodyTrackingOption(        "xrNoBodyTracking",        "Debug option. Disables OpenXR body tracking, even if it's supported."    );    QCommandLineOption xrNoPalmPoseOption(        "xrNoPalmPose",        "Debug option. Disables use of the OpenXR palm pose, even if it's supported. Falls back to the controller's grip pose."    );    QCommandLineOption graphicsAPIOption(        "graphicsAPI",        "Which graphics API to target. Supports gl45, gl41, and gles32. Final API may vary based on system support.",        "string"    );     parser.addOption(urlOption);    parser.addOption(protocolVersionOption);    parser.addOption(noUpdaterOption);    parser.addOption(checkMinSpecOption);    parser.addOption(runServerOption);    parser.addOption(listenPortOption);    parser.addOption(serverContentPathOption);    parser.addOption(overrideAppLocalDataPathOption);    parser.addOption(scriptsOption);    parser.addOption(allowMultipleInstancesOption);    parser.addOption(displaysOption);    parser.addOption(disableDisplaysOption);    parser.addOption(disableInputsOption);    parser.addOption(suppressSettingsResetOption);    parser.addOption(oculusStoreOption);    parser.addOption(standaloneOption);    parser.addOption(disableWatchdogOption);    parser.addOption(systemCursorOption);    parser.addOption(concurrentDownloadsOption);    parser.addOption(avatarURLOption);    parser.addOption(replaceAvatarURLOption);    parser.addOption(setBookmarkOption);    parser.addOption(forceCrashReportingOption);    parser.addOption(noLauncherOption);    parser.addOption(responseTokensOption);    parser.addOption(displayNameOption);    parser.addOption(noLoginOption);    parser.addOption(overrideScriptsPathOption);    parser.addOption(defaultScriptsOverrideOption);    parser.addOption(traceFileOption);    parser.addOption(traceDurationOption);    parser.addOption(clockSkewOption);    parser.addOption(testScriptOption);    parser.addOption(testResultsLocationOption);    parser.addOption(quitWhenFinishedOption);    parser.addOption(fastHeartbeatOption);    parser.addOption(logOption);    parser.addOption(abortAfterStartupOption);    parser.addOption(abortAfterInitOption);    parser.addOption(getPluginsOption);    parser.addOption(getProtocolVersionHashOption);    parser.addOption(getProtocolVersionDataOption);    parser.addOption(useExperimentalXROption);    parser.addOption(xrNoHandTrackingOption);    parser.addOption(xrNoPalmPoseOption);    parser.addOption(graphicsAPIOption);     QString applicationPath;    // A temporary application instance is needed to get the location of the running executable    // Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)    // If we wanted to avoid the QCoreApplication, we would need to write our own    // cross-platform implementation.    {        QCoreApplication tempApp(argc, const_cast<char**>(argv));         parser.process(QCoreApplication::arguments());  // Must be run after QCoreApplication is initalised. #ifdef Q_OS_OSX        if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) {            applicationPath = QCoreApplication::applicationDirPath() + "/../../../";        } else {            applicationPath = QCoreApplication::applicationDirPath();        }#else        applicationPath = QCoreApplication::applicationDirPath();#endif    }     // TODO: We need settings for Application, but Settings needs an Application    // to handle events. Needs splitting into two parts: enough initialization    // for Application to work, and then thread start afterwards.    Setting::init();#ifdef NDEBUG    // Fail if asserts are enabled on release build.    Q_ASSERT_X(false, "Interface", "This is not a debug build, but somehow Q_ASSERTs are enabled. \               This is known to happen on Windows if QT_NO_DEBUG isn't set by us.");#endif    Application app(argcExtended, const_cast<char**>(argvExtended.data()), startupTime);     if (parser.isSet("abortAfterStartup")) {        return 99;    }     // We want to configure the logging system as early as possible    auto& logHandler = LogHandler::getInstance();     if (parser.isSet(logOption)) {        if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) {            QCoreApplication mockApp(argc, const_cast<char**>(argv));  // required for call to showHelp()            parser.showHelp();            Q_UNREACHABLE();        }    }     app.initializePluginManager(parser);     if (parser.isSet(getPluginsOption)) {        auto pluginManager = PluginManager::getInstance();         QJsonObject pluginsJson;        for (const auto &plugin : pluginManager->getPluginInfo()) {            QJsonObject data;            data["data"] = plugin.metaData;            data["loaded"] = plugin.loaded;            data["disabled"] = plugin.disabled;            data["filteredOut"] = plugin.filteredOut;            data["wrongVersion"] = plugin.wrongVersion;            pluginsJson[plugin.name] = data;        }         QJsonObject inputJson;        for (const auto &plugin : pluginManager->getInputPlugins()) {            QJsonObject data;            data["subdeviceNames"] = QJsonArray::fromStringList(plugin->getSubdeviceNames());            data["deviceName"] = plugin->getDeviceName();            data["configurable"] = plugin->configurable();            data["isHandController"] = plugin->isHandController();            data["isHeadController"] = plugin->isHeadController();            data["isActive"] = plugin->isActive();            data["isSupported"] = plugin->isSupported();             inputJson[plugin->getName()] = data;        }         QJsonObject displayJson;

Lines 1–500 of 878.