mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
Merge pull request #716 from daleglass-overte/reorganize-startup
Reorganize startup to allow more control over plugins
This commit is contained in:
commit
36c700d175
6 changed files with 572 additions and 154 deletions
|
@ -724,8 +724,8 @@ extern DisplayPluginList getDisplayPlugins();
|
|||
extern InputPluginList getInputPlugins();
|
||||
extern void saveInputPluginSettings(const InputPluginList& plugins);
|
||||
|
||||
bool setupEssentials(int& argc, char** argv, const QCommandLineParser& parser, bool runningMarkerExisted) {
|
||||
qInstallMessageHandler(messageHandler);
|
||||
bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted) {
|
||||
|
||||
|
||||
|
||||
const int listenPort = parser.isSet("listenPort") ? parser.value("listenPort").toInt() : INVALID_PORT;
|
||||
|
@ -743,6 +743,7 @@ bool setupEssentials(int& argc, char** argv, const QCommandLineParser& parser, b
|
|||
|
||||
bool previousSessionCrashed { false };
|
||||
if (!inTestMode) {
|
||||
// TODO: FIX
|
||||
previousSessionCrashed = CrashRecoveryHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||
}
|
||||
|
||||
|
@ -763,13 +764,12 @@ bool setupEssentials(int& argc, char** argv, const QCommandLineParser& parser, b
|
|||
}
|
||||
}
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
|
||||
|
||||
DependencyManager::set<ScriptInitializers>();
|
||||
DependencyManager::set<PluginManager>();
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
||||
pluginManager->setDisplayPluginProvider([] { return getDisplayPlugins(); });
|
||||
pluginManager->setInputPluginSettingsPersister([](const InputPluginList& plugins) { saveInputPluginSettings(plugins); });
|
||||
if (auto steamClient = pluginManager->getSteamClientPlugin()) {
|
||||
steamClient->init();
|
||||
}
|
||||
|
@ -777,6 +777,7 @@ bool setupEssentials(int& argc, char** argv, const QCommandLineParser& parser, b
|
|||
oculusPlatform->init();
|
||||
}
|
||||
|
||||
|
||||
PROFILE_SET_THREAD_NAME("Main Thread");
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
@ -993,8 +994,7 @@ bool Application::initMenu() {
|
|||
Application::Application(
|
||||
int& argc, char** argv,
|
||||
const QCommandLineParser& parser,
|
||||
QElapsedTimer& startupTimer,
|
||||
bool runningMarkerExisted
|
||||
QElapsedTimer& startupTimer
|
||||
) :
|
||||
QApplication(argc, argv),
|
||||
_window(new MainWindow(desktop())),
|
||||
|
@ -1004,10 +1004,7 @@ Application::Application(
|
|||
#ifndef Q_OS_ANDROID
|
||||
_logger(new FileLogger(this)),
|
||||
#endif
|
||||
_previousSessionCrashed(setupEssentials(argc, argv, parser, runningMarkerExisted)),
|
||||
_entitySimulation(std::make_shared<PhysicalEntitySimulation>()),
|
||||
_physicsEngine(std::make_shared<PhysicsEngine>(Vectors::ZERO)),
|
||||
_entityClipboard(std::make_shared<EntityTree>()),
|
||||
_previousSessionCrashed(false), //setupEssentials(parser, false)),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
|
||||
|
@ -1032,12 +1029,72 @@ Application::Application(
|
|||
_snapshotSound(nullptr),
|
||||
_sampleSound(nullptr)
|
||||
{
|
||||
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
|
||||
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
|
||||
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
|
||||
|
||||
LogHandler::getInstance().moveToThread(thread());
|
||||
LogHandler::getInstance().setupRepeatedMessageFlusher();
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
DependencyManager::set<PathUtils>();
|
||||
}
|
||||
|
||||
void Application::initializePluginManager(const QCommandLineParser& parser) {
|
||||
DependencyManager::set<PluginManager>();
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
|
||||
// To avoid any confusion: the getInputPlugins and getDisplayPlugins are not the ones
|
||||
// from PluginManager, but functions exported by input-plugins/InputPlugin.cpp and
|
||||
// display-plugins/DisplayPlugin.cpp.
|
||||
//
|
||||
// These functions provide the plugin manager with static default plugins.
|
||||
pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
|
||||
pluginManager->setDisplayPluginProvider([] { return getDisplayPlugins(); });
|
||||
pluginManager->setInputPluginSettingsPersister([](const InputPluginList& plugins) { saveInputPluginSettings(plugins); });
|
||||
|
||||
|
||||
// This must be a member function -- PluginManager must exist, and for that
|
||||
// QApplication must exist, or it can't find the plugin path, as QCoreApplication:applicationDirPath
|
||||
// won't work yet.
|
||||
|
||||
if (parser.isSet("display")) {
|
||||
auto preferredDisplays = parser.value("display").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Setting prefered display plugins:" << preferredDisplays;
|
||||
PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet("disableDisplayPlugins")) {
|
||||
auto disabledDisplays = parser.value("disableDisplayPlugins").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Disabling following display plugins:" << disabledDisplays;
|
||||
PluginManager::getInstance()->disableDisplays(disabledDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet("disableInputPlugins")) {
|
||||
auto disabledInputs = parser.value("disableInputPlugins").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Disabling following input plugins:" << disabledInputs;
|
||||
PluginManager::getInstance()->disableInputs(disabledInputs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Application::initialize(const QCommandLineParser &parser) {
|
||||
|
||||
//qCDebug(interfaceapp) << "Setting up essentials";
|
||||
setupEssentials(parser, _previousSessionCrashed);
|
||||
qCDebug(interfaceapp) << "Initializing application";
|
||||
|
||||
_entitySimulation = std::make_shared<PhysicalEntitySimulation>();
|
||||
_physicsEngine = std::make_shared<PhysicsEngine>(Vectors::ZERO);
|
||||
_entityClipboard = std::make_shared<EntityTree>();
|
||||
_octreeProcessor = std::make_shared<OctreePacketProcessor>();
|
||||
_entityEditSender = std::make_shared<EntityEditPacketSender>();
|
||||
_graphicsEngine = std::make_shared<GraphicsEngine>();
|
||||
_applicationOverlay = std::make_shared<ApplicationOverlay>();
|
||||
|
||||
|
||||
|
||||
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
|
||||
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
|
||||
|
||||
|
||||
{
|
||||
if (parser.isSet("testScript")) {
|
||||
|
@ -1405,7 +1462,7 @@ Application::Application(
|
|||
connect(myAvatar.get(), &MyAvatar::positionGoneTo, this, [this] {
|
||||
if (!_physicsEnabled) {
|
||||
// when we arrive somewhere without physics enabled --> startSafeLanding
|
||||
_octreeProcessor.startSafeLanding();
|
||||
_octreeProcessor->startSafeLanding();
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
|
@ -1578,9 +1635,9 @@ Application::Application(
|
|||
qCDebug(interfaceapp, "init() complete.");
|
||||
|
||||
// create thread for parsing of octree data independent of the main network and rendering threads
|
||||
_octreeProcessor.initialize(_enableProcessOctreeThread);
|
||||
connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
||||
_entityEditSender.initialize(_enableProcessOctreeThread);
|
||||
_octreeProcessor->initialize(_enableProcessOctreeThread);
|
||||
connect(_octreeProcessor.get(), &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
||||
_entityEditSender->initialize(_enableProcessOctreeThread);
|
||||
|
||||
_idleLoopStdev.reset();
|
||||
|
||||
|
@ -1698,7 +1755,7 @@ Application::Application(
|
|||
userActivityLogger.logAction("launch", properties);
|
||||
}
|
||||
|
||||
_entityEditSender.setMyAvatar(myAvatar.get());
|
||||
_entityEditSender->setMyAvatar(myAvatar.get());
|
||||
|
||||
// The entity octree will have to know about MyAvatar for the parentJointName import
|
||||
getEntities()->getTree()->setMyAvatar(myAvatar);
|
||||
|
@ -1707,7 +1764,7 @@ Application::Application(
|
|||
// For now we're going to set the PPS for outbound packets to be super high, this is
|
||||
// probably not the right long term solution. But for now, we're going to do this to
|
||||
// allow you to move an entity around in your hand
|
||||
_entityEditSender.setPacketsPerSecond(3000); // super high!!
|
||||
_entityEditSender->setPacketsPerSecond(3000); // super high!!
|
||||
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
@ -2375,7 +2432,7 @@ Application::Application(
|
|||
|
||||
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
||||
connect(_window, SIGNAL(windowMinimizedChanged(bool)), this, SLOT(windowMinimizedChanged(bool)));
|
||||
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
|
||||
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)_sessionRunTimer.elapsed() / 1000.0);
|
||||
|
||||
EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() {
|
||||
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
|
||||
|
@ -2572,7 +2629,7 @@ Application::Application(
|
|||
}
|
||||
|
||||
_pendingIdleEvent = false;
|
||||
_graphicsEngine.startup();
|
||||
_graphicsEngine->startup();
|
||||
|
||||
qCDebug(interfaceapp) << "Directory Service session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
|
||||
|
||||
|
@ -2879,43 +2936,59 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
Application::~Application() {
|
||||
// remove avatars from physics engine
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
avatarManager->clearOtherAvatars();
|
||||
auto myCharacterController = getMyAvatar()->getCharacterController();
|
||||
myCharacterController->clearDetailedMotionStates();
|
||||
if (auto avatarManager = DependencyManager::get<AvatarManager>()) {
|
||||
// AvatarManager may not yet exist in case of an early exit
|
||||
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
avatarManager->deleteAllAvatars();
|
||||
avatarManager->clearOtherAvatars();
|
||||
auto myCharacterController = getMyAvatar()->getCharacterController();
|
||||
myCharacterController->clearDetailedMotionStates();
|
||||
|
||||
_physicsEngine->setCharacterController(nullptr);
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
avatarManager->deleteAllAvatars();
|
||||
}
|
||||
|
||||
if (_physicsEngine) {
|
||||
_physicsEngine->setCharacterController(nullptr);
|
||||
}
|
||||
|
||||
// the _shapeManager should have zero references
|
||||
_shapeManager.collectGarbage();
|
||||
assert(_shapeManager.getNumShapes() == 0);
|
||||
|
||||
// shutdown graphics engine
|
||||
_graphicsEngine.shutdown();
|
||||
if (_graphicsEngine) {
|
||||
// shutdown graphics engine
|
||||
_graphicsEngine->shutdown();
|
||||
}
|
||||
|
||||
_gameWorkload.shutdown();
|
||||
|
||||
DependencyManager::destroy<Preferences>();
|
||||
PlatformHelper::shutdown();
|
||||
|
||||
_entityClipboard->eraseAllOctreeElements();
|
||||
_entityClipboard.reset();
|
||||
|
||||
_octreeProcessor.terminate();
|
||||
_entityEditSender.terminate();
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
steamClient->shutdown();
|
||||
if (_entityClipboard) {
|
||||
_entityClipboard->eraseAllOctreeElements();
|
||||
_entityClipboard.reset();
|
||||
}
|
||||
|
||||
if (auto oculusPlatform = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
oculusPlatform->shutdown();
|
||||
if (_octreeProcessor) {
|
||||
_octreeProcessor->terminate();
|
||||
}
|
||||
|
||||
if (_entityEditSender) {
|
||||
_entityEditSender->terminate();
|
||||
}
|
||||
|
||||
if (auto pluginManager = PluginManager::getInstance()) {
|
||||
if (auto steamClient = pluginManager->getSteamClientPlugin()) {
|
||||
steamClient->shutdown();
|
||||
}
|
||||
|
||||
if (auto oculusPlatform = pluginManager->getOculusPlatformPlugin()) {
|
||||
oculusPlatform->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
DependencyManager::destroy<PluginManager>();
|
||||
|
@ -2943,7 +3016,9 @@ Application::~Application() {
|
|||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScreenshareScriptingInterface>();
|
||||
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
if (auto resourceManager = DependencyManager::get<ResourceManager>()) {
|
||||
resourceManager->cleanup();
|
||||
}
|
||||
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
|
@ -2957,13 +3032,14 @@ Application::~Application() {
|
|||
_window->deleteLater();
|
||||
|
||||
// make sure that the quit event has finished sending before we take the application down
|
||||
auto closeEventSender = DependencyManager::get<CloseEventSender>();
|
||||
while (!closeEventSender->hasFinishedQuitEvent() && !closeEventSender->hasTimedOutQuitEvent()) {
|
||||
// sleep a little so we're not spinning at 100%
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
if (auto closeEventSender = DependencyManager::get<CloseEventSender>()) {
|
||||
while (!closeEventSender->hasFinishedQuitEvent() && !closeEventSender->hasTimedOutQuitEvent()) {
|
||||
// sleep a little so we're not spinning at 100%
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
// quit the thread used by the closure event sender
|
||||
closeEventSender->thread()->quit();
|
||||
}
|
||||
// quit the thread used by the closure event sender
|
||||
closeEventSender->thread()->quit();
|
||||
|
||||
// Can't log to file past this point, FileLogger about to be deleted
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
@ -3103,7 +3179,7 @@ void Application::initializeGL() {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_glWidget->swapBuffers();
|
||||
|
||||
_graphicsEngine.initializeGPU(_glWidget);
|
||||
_graphicsEngine->initializeGPU(_glWidget);
|
||||
}
|
||||
|
||||
void Application::initializeDisplayPlugins() {
|
||||
|
@ -3115,7 +3191,7 @@ void Application::initializeDisplayPlugins() {
|
|||
// Once time initialization code
|
||||
DisplayPluginPointer targetDisplayPlugin;
|
||||
for(const auto& displayPlugin : displayPlugins) {
|
||||
displayPlugin->setContext(_graphicsEngine.getGPUContext());
|
||||
displayPlugin->setContext(_graphicsEngine->getGPUContext());
|
||||
if (displayPlugin->getName() == lastActiveDisplayPluginName) {
|
||||
targetDisplayPlugin = displayPlugin;
|
||||
}
|
||||
|
@ -3167,7 +3243,7 @@ void Application::initializeDisplayPlugins() {
|
|||
void Application::initializeRenderEngine() {
|
||||
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
|
||||
DeadlockWatchdogThread::withPause([&] {
|
||||
_graphicsEngine.initializeRender();
|
||||
_graphicsEngine->initializeRender();
|
||||
DependencyManager::get<Keyboard>()->registerKeyboardHighlighting();
|
||||
});
|
||||
}
|
||||
|
@ -3424,7 +3500,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||
surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
surfaceContext->setContextProperty("FrameTimings", &_graphicsEngine._frameTimingsScriptingInterface);
|
||||
surfaceContext->setContextProperty("FrameTimings", &_graphicsEngine->_frameTimingsScriptingInterface);
|
||||
surfaceContext->setContextProperty("Rates", new RatesScriptingInterface(this));
|
||||
|
||||
surfaceContext->setContextProperty("TREE_SCALE", TREE_SCALE);
|
||||
|
@ -4060,7 +4136,7 @@ std::map<QString, QString> Application::prepareServerlessDomainContents(QUrl dom
|
|||
bool success = tmpTree->readFromByteArray(domainURL.toString(), data);
|
||||
if (success) {
|
||||
tmpTree->reaverageOctreeElements();
|
||||
tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), "domain", 0, 0, 0);
|
||||
tmpTree->sendEntities(_entityEditSender.get(), getEntities()->getTree(), "domain", 0, 0, 0);
|
||||
}
|
||||
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
|
||||
|
||||
|
@ -4130,8 +4206,8 @@ void Application::onPresent(quint32 frameCount) {
|
|||
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
||||
}
|
||||
expected = false;
|
||||
if (_graphicsEngine.checkPendingRenderEvent() && !isAboutToQuit()) {
|
||||
postEvent(_graphicsEngine._renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||
if (_graphicsEngine->checkPendingRenderEvent() && !isAboutToQuit()) {
|
||||
postEvent(_graphicsEngine->_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4201,7 +4277,9 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) {
|
|||
}
|
||||
|
||||
bool Application::notify(QObject * object, QEvent * event) {
|
||||
if (thread() == QThread::currentThread()) {
|
||||
if (thread() == QThread::currentThread() && _profilingInitialized ) {
|
||||
// _profilingInitialized gets set once we're reading for profiling.
|
||||
// this prevents a deadlock due to profiling not working yet
|
||||
PROFILE_RANGE_IF_LONGER(app, "notify", 2)
|
||||
return QApplication::notify(object, event);
|
||||
}
|
||||
|
@ -5246,8 +5324,8 @@ void Application::idle() {
|
|||
PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", uint32_t, ResourceCache::getPendingRequestCount());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get<StatTracker>()->getStat("Processing").toInt());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
|
||||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_graphicsEngine.getGPUContext()->getFrameTimerGPUAverage());
|
||||
auto renderConfig = _graphicsEngine->getRenderEngine()->getConfiguration();
|
||||
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_graphicsEngine->getGPUContext()->getFrameTimerGPUAverage());
|
||||
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
|
||||
|
@ -5614,7 +5692,7 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse
|
|||
}
|
||||
|
||||
QVector<EntityItemID> Application::pasteEntities(const QString& entityHostType, float x, float y, float z) {
|
||||
return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), entityHostType, x, y, z);
|
||||
return _entityClipboard->sendEntities(_entityEditSender.get(), getEntities()->getTree(), entityHostType, x, y, z);
|
||||
}
|
||||
|
||||
void Application::init() {
|
||||
|
@ -5664,7 +5742,7 @@ void Application::init() {
|
|||
_physicsEngine->init();
|
||||
|
||||
EntityTreePointer tree = getEntities()->getTree();
|
||||
_entitySimulation->init(tree, _physicsEngine, &_entityEditSender);
|
||||
_entitySimulation->init(tree, _physicsEngine, _entityEditSender.get());
|
||||
tree->setSimulation(_entitySimulation);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
@ -5688,7 +5766,7 @@ void Application::init() {
|
|||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _graphicsEngine.getRenderScene(), _entitySimulation);
|
||||
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _graphicsEngine->getRenderScene(), _entitySimulation);
|
||||
_entitySimulation->setWorkloadSpace(getEntities()->getWorkloadSpace());
|
||||
}
|
||||
|
||||
|
@ -5860,7 +5938,7 @@ void Application::updateLOD(float deltaTime) const {
|
|||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||
if (!isThrottleRendering()) {
|
||||
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
|
||||
float engineRunTime = (float)(_graphicsEngine.getRenderEngine()->getConfiguration().get()->getCPURunTime());
|
||||
float engineRunTime = (float)(_graphicsEngine->getRenderEngine()->getConfiguration().get()->getCPURunTime());
|
||||
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
|
||||
float batchTime = getGPUContext()->getFrameTimerBatchAverage();
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
@ -5896,8 +5974,8 @@ void Application::updateThreads(float deltaTime) {
|
|||
|
||||
// parse voxel packets
|
||||
if (!_enableProcessOctreeThread) {
|
||||
_octreeProcessor.threadRoutine();
|
||||
_entityEditSender.threadRoutine();
|
||||
_octreeProcessor->threadRoutine();
|
||||
_entityEditSender->threadRoutine();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6020,7 +6098,7 @@ void Application::resetPhysicsReadyInformation() {
|
|||
_gpuTextureMemSizeStabilityCount = 0;
|
||||
_gpuTextureMemSizeAtLastCheck = 0;
|
||||
_physicsEnabled = false;
|
||||
_octreeProcessor.stopSafeLanding();
|
||||
_octreeProcessor->stopSafeLanding();
|
||||
}
|
||||
|
||||
void Application::reloadResourceCaches() {
|
||||
|
@ -6165,7 +6243,7 @@ void Application::updateSecondaryCameraViewFrustum() {
|
|||
// camera should be.
|
||||
|
||||
// Code based on SecondaryCameraJob
|
||||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
auto renderConfig = _graphicsEngine->getRenderEngine()->getConfiguration();
|
||||
assert(renderConfig);
|
||||
auto camera = dynamic_cast<SecondaryCameraJobConfig*>(renderConfig->getConfig("SecondaryCamera"));
|
||||
|
||||
|
@ -6283,7 +6361,7 @@ void Application::tryToEnablePhysics() {
|
|||
auto myAvatar = getMyAvatar();
|
||||
if (myAvatar->isReadyForPhysics()) {
|
||||
myAvatar->getCharacterController()->setPhysicsEngine(_physicsEngine);
|
||||
_octreeProcessor.resetSafeLanding();
|
||||
_octreeProcessor->resetSafeLanding();
|
||||
_physicsEnabled = true;
|
||||
setIsInterstitialMode(false);
|
||||
myAvatar->updateMotionBehaviorFromMenu();
|
||||
|
@ -6292,7 +6370,7 @@ void Application::tryToEnablePhysics() {
|
|||
}
|
||||
|
||||
void Application::update(float deltaTime) {
|
||||
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_graphicsEngine._renderFrameCount + 1);
|
||||
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_graphicsEngine->_renderFrameCount + 1);
|
||||
|
||||
if (_aboutToQuit) {
|
||||
return;
|
||||
|
@ -6309,12 +6387,12 @@ void Application::update(float deltaTime) {
|
|||
if (isServerlessMode()) {
|
||||
tryToEnablePhysics();
|
||||
} else if (_failedToConnectToEntityServer) {
|
||||
if (_octreeProcessor.safeLandingIsActive()) {
|
||||
_octreeProcessor.stopSafeLanding();
|
||||
if (_octreeProcessor->safeLandingIsActive()) {
|
||||
_octreeProcessor->stopSafeLanding();
|
||||
}
|
||||
} else {
|
||||
_octreeProcessor.updateSafeLanding();
|
||||
if (_octreeProcessor.safeLandingIsComplete()) {
|
||||
_octreeProcessor->updateSafeLanding();
|
||||
if (_octreeProcessor->safeLandingIsComplete()) {
|
||||
tryToEnablePhysics();
|
||||
}
|
||||
}
|
||||
|
@ -6801,7 +6879,7 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateRenderArgs(float deltaTime) {
|
||||
_graphicsEngine.editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
|
||||
_graphicsEngine->editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
|
||||
PerformanceTimer perfTimer("editRenderArgs");
|
||||
appRenderArgs._headPose = getHMDSensorPose();
|
||||
|
||||
|
@ -6830,7 +6908,7 @@ void Application::updateRenderArgs(float deltaTime) {
|
|||
_viewFrustum.setProjection(adjustedProjection);
|
||||
_viewFrustum.calculate();
|
||||
}
|
||||
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getVisibilityDistance(),
|
||||
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine->getGPUContext(), lodManager->getVisibilityDistance(),
|
||||
lodManager->getBoundaryLevelAdjust(), lodManager->getLODFarHalfAngleTan(), lodManager->getLODNearHalfAngleTan(),
|
||||
lodManager->getLODFarDistance(), lodManager->getLODNearDistance(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE);
|
||||
|
@ -6969,7 +7047,7 @@ int Application::sendNackPackets() {
|
|||
|
||||
// if there are octree packets from this node that are waiting to be processed,
|
||||
// don't send a NACK since the missing packets may be among those waiting packets.
|
||||
if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) {
|
||||
if (_octreeProcessor->hasPacketsToProcessFrom(nodeUUID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7011,7 +7089,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) {
|
|||
|
||||
const bool isModifiedQuery = !_physicsEnabled;
|
||||
if (isModifiedQuery) {
|
||||
if (!_octreeProcessor.safeLandingIsActive()) {
|
||||
if (!_octreeProcessor->safeLandingIsActive()) {
|
||||
// don't send the octreeQuery until SafeLanding knows it has started
|
||||
return;
|
||||
}
|
||||
|
@ -7280,12 +7358,12 @@ void Application::resettingDomain() {
|
|||
void Application::nodeAdded(SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::EntityServer) {
|
||||
if (_failedToConnectToEntityServer && !_entityServerConnectionTimer.isActive()) {
|
||||
_octreeProcessor.stopSafeLanding();
|
||||
_octreeProcessor->stopSafeLanding();
|
||||
_failedToConnectToEntityServer = false;
|
||||
} else if (_entityServerConnectionTimer.isActive()) {
|
||||
_entityServerConnectionTimer.stop();
|
||||
}
|
||||
_octreeProcessor.startSafeLanding();
|
||||
_octreeProcessor->startSafeLanding();
|
||||
_entityServerConnectionTimer.setInterval(ENTITY_SERVER_CONNECTION_TIMEOUT);
|
||||
_entityServerConnectionTimer.start();
|
||||
}
|
||||
|
@ -7357,9 +7435,9 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
// OctreePacketProcessor::nodeKilled is not being called when NodeList::nodeKilled is emitted.
|
||||
// This may have to do with GenericThread::threadRoutine() blocking the QThread event loop
|
||||
|
||||
_octreeProcessor.nodeKilled(node);
|
||||
_octreeProcessor->nodeKilled(node);
|
||||
|
||||
_entityEditSender.nodeKilled(node);
|
||||
_entityEditSender->nodeKilled(node);
|
||||
|
||||
if (node->getType() == NodeType::AudioMixer) {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "audioMixerKilled");
|
||||
|
@ -7448,7 +7526,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptManagerPoint
|
|||
// setup the packet sender of the script engine's scripting interfaces so
|
||||
// we can use the same ones from the application.
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->setPacketSender(&_entityEditSender);
|
||||
entityScriptingInterface->setPacketSender(_entityEditSender.get());
|
||||
entityScriptingInterface->setEntityTree(getEntities()->getTree());
|
||||
|
||||
if (property(hifi::properties::TEST).isValid()) {
|
||||
|
@ -8762,26 +8840,6 @@ void Application::sendLambdaEvent(const std::function<void()>& f) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::initPlugins(const QCommandLineParser& parser) {
|
||||
if (parser.isSet("display")) {
|
||||
auto preferredDisplays = parser.value("display").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Setting prefered display plugins:" << preferredDisplays;
|
||||
PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet("disable-displays")) {
|
||||
auto disabledDisplays = parser.value("disable-displays").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Disabling following display plugins:" << disabledDisplays;
|
||||
PluginManager::getInstance()->disableDisplays(disabledDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet("disable-inputs")) {
|
||||
auto disabledInputs = parser.value("disable-inputs").split(',', Qt::SkipEmptyParts);
|
||||
qInfo() << "Disabling following input plugins:" << disabledInputs;
|
||||
PluginManager::getInstance()->disableInputs(disabledInputs);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::shutdownPlugins() {
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,31 @@ class Application : public QApplication,
|
|||
friend class OctreePacketProcessor;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Initialize the plugin manager
|
||||
*
|
||||
* This both does the initial startup and parses arguments. This
|
||||
* is necessary because the plugin manager's options must be set
|
||||
* before any usage of it is made, or they won't apply.
|
||||
*
|
||||
* @param parser
|
||||
*/
|
||||
void initializePluginManager(const QCommandLineParser& parser);
|
||||
|
||||
/**
|
||||
* @brief Initialize everything
|
||||
*
|
||||
* This is a QApplication, and for Qt reasons it's desirable to create this object
|
||||
* as early as possible. Without that some Qt functions don't work, like QCoreApplication::applicationDirPath()
|
||||
*
|
||||
* So we keep the constructor as minimal as possible, and do the rest of the work in
|
||||
* this function.
|
||||
*/
|
||||
void initialize(const QCommandLineParser &parser);
|
||||
|
||||
void setPreviousSessionCrashed(bool value) { _previousSessionCrashed = value; }
|
||||
|
||||
// virtual functions required for PluginContainer
|
||||
virtual ui::Menu* getPrimaryMenu() override;
|
||||
virtual void requestReset() override { resetSensors(false); }
|
||||
|
@ -135,15 +160,12 @@ public:
|
|||
|
||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||
|
||||
// FIXME? Empty methods, do we still need them?
|
||||
static void initPlugins(const QCommandLineParser& parser);
|
||||
static void shutdownPlugins();
|
||||
|
||||
Application(
|
||||
int& argc, char** argv,
|
||||
const QCommandLineParser& parser,
|
||||
QElapsedTimer& startup_time,
|
||||
bool runningMarkerExisted
|
||||
QElapsedTimer& startup_time
|
||||
);
|
||||
~Application();
|
||||
|
||||
|
@ -197,16 +219,16 @@ public:
|
|||
|
||||
const ConicalViewFrustums& getConicalViews() const override { return _conicalViews; }
|
||||
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return *_octreeProcessor; }
|
||||
QSharedPointer<EntityTreeRenderer> getEntities() const { return DependencyManager::get<EntityTreeRenderer>(); }
|
||||
MainWindow* getWindow() const { return _window; }
|
||||
EntityTreePointer getEntityClipboard() const { return _entityClipboard; }
|
||||
EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; }
|
||||
std::shared_ptr<EntityEditPacketSender> getEntityEditPacketSender() { return _entityEditSender; }
|
||||
|
||||
ivec2 getMouse() const;
|
||||
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return *_applicationOverlay; }
|
||||
const ApplicationOverlay& getApplicationOverlay() const { return *_applicationOverlay; }
|
||||
CompositorHelper& getApplicationCompositor() const;
|
||||
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
@ -214,8 +236,8 @@ public:
|
|||
PerformanceManager& getPerformanceManager() { return _performanceManager; }
|
||||
RefreshRateManager& getRefreshRateManager() { return _refreshRateManager; }
|
||||
|
||||
size_t getRenderFrameCount() const { return _graphicsEngine.getRenderFrameCount(); }
|
||||
float getRenderLoopRate() const { return _graphicsEngine.getRenderLoopRate(); }
|
||||
size_t getRenderFrameCount() const { return _graphicsEngine->getRenderFrameCount(); }
|
||||
float getRenderLoopRate() const { return _graphicsEngine->getRenderLoopRate(); }
|
||||
float getNumCollisionObjects() const;
|
||||
float getTargetRenderFrameRate() const; // frames/second
|
||||
|
||||
|
@ -293,9 +315,9 @@ public:
|
|||
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
||||
int getMaxOctreePacketsPerSecond() const;
|
||||
|
||||
render::ScenePointer getMain3DScene() override { return _graphicsEngine.getRenderScene(); }
|
||||
render::EnginePointer getRenderEngine() override { return _graphicsEngine.getRenderEngine(); }
|
||||
gpu::ContextPointer getGPUContext() const { return _graphicsEngine.getGPUContext(); }
|
||||
render::ScenePointer getMain3DScene() override { return _graphicsEngine->getRenderScene(); }
|
||||
render::EnginePointer getRenderEngine() override { return _graphicsEngine->getRenderEngine(); }
|
||||
gpu::ContextPointer getGPUContext() const { return _graphicsEngine->getGPUContext(); }
|
||||
|
||||
const GameWorkload& getGameWorkload() const { return _gameWorkload; }
|
||||
|
||||
|
@ -709,8 +731,8 @@ private:
|
|||
bool _enableProcessOctreeThread;
|
||||
bool _interstitialMode { false };
|
||||
|
||||
OctreePacketProcessor _octreeProcessor;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
std::shared_ptr<OctreePacketProcessor> _octreeProcessor;
|
||||
std::shared_ptr<EntityEditPacketSender> _entityEditSender;
|
||||
|
||||
StDev _idleLoopStdev;
|
||||
float _idleLoopMeasuredJitter;
|
||||
|
@ -757,13 +779,13 @@ private:
|
|||
|
||||
GameWorkload _gameWorkload;
|
||||
|
||||
GraphicsEngine _graphicsEngine;
|
||||
std::shared_ptr<GraphicsEngine> _graphicsEngine;
|
||||
void updateRenderArgs(float deltaTime);
|
||||
|
||||
bool _disableLoginScreen { true };
|
||||
|
||||
Overlays _overlays;
|
||||
ApplicationOverlay _applicationOverlay;
|
||||
std::shared_ptr<ApplicationOverlay> _applicationOverlay;
|
||||
OverlayConductor _overlayConductor;
|
||||
|
||||
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
|
||||
|
@ -860,5 +882,7 @@ private:
|
|||
bool _crashOnShutdown { false };
|
||||
|
||||
DiscordPresence* _discordPresence{ nullptr };
|
||||
|
||||
bool _profilingInitialized { false };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -1035,8 +1035,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
|
|||
std::pair<bool, bool> zoneInteractionProperties;
|
||||
entityTree->withWriteLock([&] {
|
||||
zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties();
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
entityTree->updateEntityQueryAACube(shared_from_this(), packetSender, false, true);
|
||||
std::shared_ptr<EntityEditPacketSender> packetSender = qApp->getEntityEditPacketSender();
|
||||
entityTree->updateEntityQueryAACube(shared_from_this(), packetSender.get(), false, true);
|
||||
});
|
||||
bool isPhysicsEnabled = qApp->isPhysicsEnabled();
|
||||
bool zoneAllowsFlying = zoneInteractionProperties.first;
|
||||
|
@ -1729,7 +1729,7 @@ void MyAvatar::handleChangedAvatarEntityData() {
|
|||
entityTree->deleteEntitiesByID(entitiesToDelete);
|
||||
|
||||
// ADD real entities
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
auto packetSender = qApp->getEntityEditPacketSender();
|
||||
for (const auto& id : entitiesToAdd) {
|
||||
bool blobFailed = false;
|
||||
EntityItemProperties properties;
|
||||
|
@ -4231,7 +4231,7 @@ void MyAvatar::setSessionUUID(const QUuid& sessionUUID) {
|
|||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
auto packetSender = qApp->getEntityEditPacketSender();
|
||||
entityTree->withWriteLock([&] {
|
||||
for (const auto& entityID : avatarEntityIDs) {
|
||||
auto entity = entityTree->findEntityByID(entityID);
|
||||
|
@ -6888,7 +6888,7 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
|
|||
if (entityTree) {
|
||||
entityTree->withWriteLock([&] {
|
||||
// force an update packet
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
auto packetSender = qApp->getEntityEditPacketSender();
|
||||
packetSender->queueEditAvatarEntityMessage(entityTree, entityID);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
|
@ -33,6 +34,9 @@
|
|||
#include "MainWindow.h"
|
||||
#include "Profile.h"
|
||||
#include "LogHandler.h"
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
|
@ -63,11 +67,24 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Extend argv to enable WebGL rendering
|
||||
std::vector<const char*> argvExtended(&argv[0], &argv[argc]);
|
||||
argvExtended.push_back("--ignore-gpu-blocklist");
|
||||
#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();
|
||||
|
@ -125,12 +142,12 @@ int main(int argc, const char* argv[]) {
|
|||
"displays"
|
||||
);
|
||||
QCommandLineOption disableDisplaysOption(
|
||||
"disable-displays",
|
||||
"disableDisplayPlugins",
|
||||
"Displays to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
|
||||
"string"
|
||||
);
|
||||
QCommandLineOption disableInputsOption(
|
||||
"disable-inputs",
|
||||
"disableInputPlugins",
|
||||
"Inputs to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
|
||||
"string"
|
||||
);
|
||||
|
@ -246,6 +263,19 @@ int main(int argc, const char* argv[]) {
|
|||
"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."
|
||||
);
|
||||
|
||||
// "--qmljsdebugger", which appears in output from "--help-all".
|
||||
// Those below don't seem to be optional.
|
||||
// --ignore-gpu-blacklist
|
||||
|
@ -288,6 +318,10 @@ int main(int argc, const char* argv[]) {
|
|||
parser.addOption(quitWhenFinishedOption);
|
||||
parser.addOption(fastHeartbeatOption);
|
||||
parser.addOption(logOption);
|
||||
parser.addOption(abortAfterStartupOption);
|
||||
parser.addOption(abortAfterInitOption);
|
||||
parser.addOption(getPluginsOption);
|
||||
|
||||
|
||||
QString applicationPath;
|
||||
// A temporary application instance is needed to get the location of the running executable
|
||||
|
@ -310,6 +344,16 @@ int main(int argc, const char* argv[]) {
|
|||
#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();
|
||||
Application app(argcExtended, const_cast<char**>(argvExtended.data()), parser, startupTime);
|
||||
|
||||
if (parser.isSet("abortAfterStartup")) {
|
||||
return 99;
|
||||
}
|
||||
|
||||
// We want to configure the logging system as early as possible
|
||||
auto& logHandler = LogHandler::getInstance();
|
||||
|
||||
|
@ -321,6 +365,75 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (const auto &plugin : pluginManager->getDisplayPlugins()) {
|
||||
QJsonObject data;
|
||||
data["isHmd"] = plugin->isHmd();
|
||||
data["isStereo"] = plugin->isStereo();
|
||||
data["targetFramerate"] = plugin->getTargetFrameRate();
|
||||
data["hasAsyncReprojection"] = plugin->hasAsyncReprojection();
|
||||
data["isActive"] = plugin->isActive();
|
||||
data["isSupported"] = plugin->isSupported();
|
||||
|
||||
displayJson[plugin->getName()] = data;
|
||||
}
|
||||
|
||||
QJsonObject codecsJson;
|
||||
for (const auto &plugin : pluginManager->getCodecPlugins()) {
|
||||
QJsonObject data;
|
||||
data["isActive"] = plugin->isActive();
|
||||
data["isSupported"] = plugin->isSupported();
|
||||
|
||||
codecsJson[plugin->getName()] = data;
|
||||
}
|
||||
|
||||
QJsonObject platformsJson;
|
||||
platformsJson["steamAvailable"] = (pluginManager->getSteamClientPlugin() != nullptr);
|
||||
platformsJson["oculusAvailable"] = (pluginManager->getOculusPlatformPlugin() != nullptr);
|
||||
|
||||
QJsonObject root;
|
||||
root["plugins"] = pluginsJson;
|
||||
root["inputs"] = inputJson;
|
||||
root["displays"] = displayJson;
|
||||
root["codecs"] = codecsJson;
|
||||
root["platforms"] = platformsJson;
|
||||
|
||||
std::cout << QJsonDocument(root).toJson().toStdString() << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Act on arguments for early termination.
|
||||
if (parser.isSet(versionOption)) {
|
||||
parser.showVersion();
|
||||
|
@ -407,10 +520,9 @@ int main(int argc, const char* argv[]) {
|
|||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
|
||||
QElapsedTimer startupTime;
|
||||
startupTime.start();
|
||||
|
||||
Setting::init();
|
||||
|
||||
|
||||
|
||||
// Instance UserActivityLogger now that the settings are loaded
|
||||
auto& ual = UserActivityLogger::getInstance();
|
||||
|
@ -549,7 +661,7 @@ int main(int argc, const char* argv[]) {
|
|||
// Oculus initialization MUST PRECEDE OpenGL context creation.
|
||||
// The nature of the Application constructor means this has to be either here,
|
||||
// or in the main window ctor, before GL startup.
|
||||
Application::initPlugins(parser);
|
||||
//app.configurePlugins(parser);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// If we're running in steam mode, we need to do an explicit check to ensure we're up to the required min spec
|
||||
|
@ -587,17 +699,10 @@ int main(int argc, const char* argv[]) {
|
|||
SandboxUtils::runLocalSandbox(serverContentPath, true, noUpdater);
|
||||
}
|
||||
|
||||
// Extend argv to enable WebGL rendering
|
||||
std::vector<const char*> argvExtended(&argv[0], &argv[argc]);
|
||||
argvExtended.push_back("--ignore-gpu-blocklist");
|
||||
#ifdef Q_OS_ANDROID
|
||||
argvExtended.push_back("--suppress-settings-reset");
|
||||
#endif
|
||||
int argcExtended = (int)argvExtended.size();
|
||||
|
||||
PROFILE_SYNC_END(startup, "main startup", "");
|
||||
PROFILE_SYNC_BEGIN(startup, "app full ctor", "");
|
||||
Application app(argcExtended, const_cast<char**>(argvExtended.data()), parser, startupTime, runningMarkerExisted);
|
||||
app.setPreviousSessionCrashed(runningMarkerExisted);
|
||||
app.initialize(parser);
|
||||
PROFILE_SYNC_END(startup, "app full ctor", "");
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
|
@ -665,6 +770,9 @@ int main(int argc, const char* argv[]) {
|
|||
translator.load("i18n/interface_en");
|
||||
app.installTranslator(&translator);
|
||||
qCDebug(interfaceapp, "Created QT Application.");
|
||||
if (parser.isSet("abortAfterInit")) {
|
||||
return 99;
|
||||
}
|
||||
exitCode = app.exec();
|
||||
server.close();
|
||||
|
||||
|
|
|
@ -72,12 +72,13 @@ int getPluginInterfaceVersionFromMetaData(const QJsonObject& object) {
|
|||
QStringList preferredDisplayPlugins;
|
||||
QStringList disabledDisplays;
|
||||
QStringList disabledInputs;
|
||||
std::vector<PluginManager::PluginInfo> pluginInfo;
|
||||
|
||||
bool isDisabled(QJsonObject metaData) {
|
||||
auto name = getPluginNameFromMetaData(metaData);
|
||||
auto iid = getPluginIIDFromMetaData(metaData);
|
||||
|
||||
if (iid == DisplayProvider_iid) {
|
||||
if (iid == DisplayProvider_iid || iid == SteamClientProvider_iid || iid == OculusPlatformProvider_iid) {
|
||||
return disabledDisplays.contains(name);
|
||||
} else if (iid == InputProvider_iid) {
|
||||
return disabledInputs.contains(name);
|
||||
|
@ -126,18 +127,28 @@ int PluginManager::instantiate() {
|
|||
qCDebug(plugins) << "Attempting plugin" << qPrintable(plugin);
|
||||
auto loader = QSharedPointer<QPluginLoader>::create(pluginPath + plugin);
|
||||
const QJsonObject pluginMetaData = loader->metaData();
|
||||
|
||||
PluginInfo info;
|
||||
info.name = plugin;
|
||||
info.metaData = pluginMetaData;
|
||||
|
||||
#if defined(HIFI_PLUGINMANAGER_DEBUG)
|
||||
QJsonDocument metaDataDoc(pluginMetaData);
|
||||
qCInfo(plugins) << "Metadata for " << qPrintable(plugin) << ": " << QString(metaDataDoc.toJson());
|
||||
#endif
|
||||
if (isDisabled(pluginMetaData)) {
|
||||
qCWarning(plugins) << "Plugin" << qPrintable(plugin) << "is disabled";
|
||||
info.disabled = true;
|
||||
pluginInfo.push_back(info);
|
||||
|
||||
// Skip this one, it's disabled
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_pluginFilter(pluginMetaData)) {
|
||||
qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "doesn't pass provided filter";
|
||||
info.filteredOut = true;
|
||||
pluginInfo.push_back(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -145,16 +156,22 @@ int PluginManager::instantiate() {
|
|||
qCWarning(plugins) << "Plugin" << qPrintable(plugin) << "interface version doesn't match, not loading:"
|
||||
<< getPluginInterfaceVersionFromMetaData(pluginMetaData)
|
||||
<< "doesn't match" << HIFI_PLUGIN_INTERFACE_VERSION;
|
||||
|
||||
info.wrongVersion = true;
|
||||
pluginInfo.push_back(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loader->load()) {
|
||||
qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "loaded successfully";
|
||||
info.loaded = true;
|
||||
loadedPlugins.push_back(loader);
|
||||
} else {
|
||||
qCDebug(plugins) << "Plugin" << qPrintable(plugin) << "failed to load:";
|
||||
qCDebug(plugins) << " " << qPrintable(loader->errorString());
|
||||
}
|
||||
|
||||
pluginInfo.push_back(info);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "pluginPath does not exit..." << pluginDir;
|
||||
|
@ -163,6 +180,11 @@ int PluginManager::instantiate() {
|
|||
return loadedPlugins;
|
||||
}
|
||||
|
||||
std::vector<PluginManager::PluginInfo> PluginManager::getPluginInfo() const {
|
||||
getLoadedPlugins(); // This builds the pluginInfo list
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
const CodecPluginList& PluginManager::getCodecPlugins() {
|
||||
static CodecPluginList codecPlugins;
|
||||
static std::once_flag once;
|
||||
|
@ -272,14 +294,6 @@ DisplayPluginList PluginManager::getAllDisplayPlugins() {
|
|||
return _displayPlugins;
|
||||
}
|
||||
|
||||
void PluginManager::disableDisplayPlugin(const QString& name) {
|
||||
auto it = std::remove_if(_displayPlugins.begin(), _displayPlugins.end(), [&](const DisplayPluginPointer& plugin){
|
||||
return plugin->getName() == name;
|
||||
});
|
||||
_displayPlugins.erase(it, _displayPlugins.end());
|
||||
}
|
||||
|
||||
|
||||
const InputPluginList& PluginManager::getInputPlugins() {
|
||||
static std::once_flag once;
|
||||
static auto deviceAddedCallback = [&](QString deviceName) {
|
||||
|
|
|
@ -12,54 +12,268 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Forward.h"
|
||||
|
||||
class QPluginLoader;
|
||||
using PluginManagerPointer = QSharedPointer<PluginManager>;
|
||||
|
||||
/**
|
||||
* @brief Manages loadable plugins
|
||||
*
|
||||
* The current implementation does initialization only once, as soon as it's needed.
|
||||
* Once things are initialized the configuration is made permanent.
|
||||
*
|
||||
* Both loadable and statically modules are supported. Static modules have to be provided
|
||||
* with setDisplayPluginProvider, setInputPluginProvider and setCodecPluginProvider.
|
||||
*
|
||||
* @warning Users of the PluginManager must take care to do any configuration very early
|
||||
* on, because changes become impossible once initialization is done. Plugins can't be
|
||||
* added or removed once that happens.
|
||||
*
|
||||
* Initialization is performed in the getDisplayPlugins, getInputPlugins and getCodecPlugins
|
||||
* functions.
|
||||
*/
|
||||
class PluginManager : public QObject, public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Information about known plugins
|
||||
*
|
||||
*/
|
||||
struct PluginInfo {
|
||||
/**
|
||||
* @brief Plugin metadata
|
||||
*/
|
||||
QJsonObject metaData;
|
||||
|
||||
/**
|
||||
* @brief Filename
|
||||
*
|
||||
*/
|
||||
QString name;
|
||||
|
||||
/**
|
||||
* @brief Whether the plugin has been disabled
|
||||
*
|
||||
*/
|
||||
bool disabled = false;
|
||||
|
||||
/**
|
||||
* @brief Whether the plugin has been filtered out by a filter
|
||||
*
|
||||
*/
|
||||
bool filteredOut = false;
|
||||
|
||||
/**
|
||||
* @brief Whether the plugin has been not loaded because it's the wrong version
|
||||
*
|
||||
*/
|
||||
bool wrongVersion = false;
|
||||
|
||||
/**
|
||||
* @brief Whether the plugin has been loaded successfully
|
||||
*
|
||||
*/
|
||||
bool loaded = false;
|
||||
};
|
||||
|
||||
|
||||
static PluginManagerPointer getInstance();
|
||||
|
||||
/**
|
||||
* @brief Get the list of display plugins
|
||||
*
|
||||
* @note Calling this function will perform initialization and
|
||||
* connects events to all the known the plugins on the first call.
|
||||
*
|
||||
* @return const DisplayPluginList&
|
||||
*/
|
||||
const DisplayPluginList& getDisplayPlugins();
|
||||
|
||||
/**
|
||||
* @brief Get the list of input plugins
|
||||
*
|
||||
* @note Calling this function will perform initialization and
|
||||
* connects events to all the known the plugins on the first call.
|
||||
*
|
||||
* @return const InputPluginList&
|
||||
*/
|
||||
const InputPluginList& getInputPlugins();
|
||||
|
||||
/**
|
||||
* @brief Get the list of audio codec plugins
|
||||
*
|
||||
* @note Calling this function will perform initialization and
|
||||
* connects events to all the known the plugins on the first call.
|
||||
*
|
||||
* @return const CodecPluginList&
|
||||
*/
|
||||
const CodecPluginList& getCodecPlugins();
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to the Steam client plugin
|
||||
*
|
||||
* This may return a null pointer if Steam support isn't built in.
|
||||
*
|
||||
* @return const SteamClientPluginPointer
|
||||
*/
|
||||
const SteamClientPluginPointer getSteamClientPlugin();
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to the Oculus Platform Plugin
|
||||
*
|
||||
* This may return a null pointer if Oculus support isn't built in.
|
||||
*
|
||||
* @return const OculusPlatformPluginPointer
|
||||
*/
|
||||
const OculusPlatformPluginPointer getOculusPlatformPlugin();
|
||||
|
||||
/**
|
||||
* @brief Returns the list of preferred display plugins
|
||||
*
|
||||
* The preferred display plugins are set by setPreferredDisplayPlugins.
|
||||
*
|
||||
* @return DisplayPluginList
|
||||
*/
|
||||
DisplayPluginList getPreferredDisplayPlugins();
|
||||
|
||||
/**
|
||||
* @brief Sets the list of preferred display plugins
|
||||
*
|
||||
* @note This must be called early, before any call to getPreferredDisplayPlugins.
|
||||
*
|
||||
* @param displays
|
||||
*/
|
||||
void setPreferredDisplayPlugins(const QStringList& displays);
|
||||
|
||||
void disableDisplayPlugin(const QString& name);
|
||||
/**
|
||||
* @brief Disable a list of displays
|
||||
*
|
||||
* This adds the display to a list of displays not to be used.
|
||||
*
|
||||
* @param displays
|
||||
*/
|
||||
void disableDisplays(const QStringList& displays);
|
||||
|
||||
/**
|
||||
* @brief Disable a list of inputs
|
||||
*
|
||||
* This adds the input to a list of inputs not to be used.
|
||||
* @param inputs
|
||||
*/
|
||||
void disableInputs(const QStringList& inputs);
|
||||
|
||||
/**
|
||||
* @brief Save the settings
|
||||
*
|
||||
*/
|
||||
void saveSettings();
|
||||
|
||||
/**
|
||||
* @brief Set the container for plugins
|
||||
*
|
||||
* This will be passed to all active plugins on initialization.
|
||||
*
|
||||
* @param container
|
||||
*/
|
||||
void setContainer(PluginContainer* container) { _container = container; }
|
||||
|
||||
int instantiate();
|
||||
void shutdown();
|
||||
|
||||
// Application that have statically linked plugins can expose them to the plugin manager with these function
|
||||
|
||||
/**
|
||||
* @brief Provide a list of statically linked plugins.
|
||||
*
|
||||
* This is used to provide a list of statically linked plugins to the plugin manager.
|
||||
*
|
||||
* @note This must be called very early on, and only works once. Once the plugin manager
|
||||
* builds its internal list of plugins, the final list becomes set in stone.
|
||||
*
|
||||
* @param provider A std::function that returns a list of display plugins
|
||||
*/
|
||||
void setDisplayPluginProvider(const DisplayPluginProvider& provider);
|
||||
|
||||
/**
|
||||
* @brief Provide a list of statically linked plugins.
|
||||
*
|
||||
* This is used to provide a list of statically linked plugins to the plugin manager.
|
||||
*
|
||||
* @note This must be called very early on, and only works once. Once the plugin manager
|
||||
* builds its internal list of plugins, the final list becomes set in stone.
|
||||
*
|
||||
* @param provider A std::function that returns a list of input plugins
|
||||
*/
|
||||
void setInputPluginProvider(const InputPluginProvider& provider);
|
||||
|
||||
/**
|
||||
* @brief Provide a list of statically linked plugins.
|
||||
*
|
||||
* This is used to provide a list of statically linked plugins to the plugin manager.
|
||||
*
|
||||
* @note This must be called very early on, and only works once. Once the plugin manager
|
||||
* builds its internal list of plugins, the final list becomes set in stone.
|
||||
*
|
||||
* @param provider A std::function that returns a list of codec plugins
|
||||
*/
|
||||
void setCodecPluginProvider(const CodecPluginProvider& provider);
|
||||
|
||||
/**
|
||||
* @brief Set the input plugin persister
|
||||
*
|
||||
* @param persister A std::function that saves input plugin settings
|
||||
*/
|
||||
void setInputPluginSettingsPersister(const InputPluginSettingsPersister& persister);
|
||||
|
||||
/**
|
||||
* @brief Get the list of running input devices
|
||||
*
|
||||
* @return QStringList List of input devices in running state
|
||||
*/
|
||||
QStringList getRunningInputDeviceNames() const;
|
||||
|
||||
using PluginFilter = std::function<bool(const QJsonObject&)>;
|
||||
|
||||
/**
|
||||
* @brief Set the plugin filter that determines whether a plugin will be used or not
|
||||
*
|
||||
* @note This must be called very early on. Once the plugin manager
|
||||
* builds its internal list of plugins, the final list becomes set in stone.
|
||||
*
|
||||
* As of writing, this is used in the audio mixer.
|
||||
*
|
||||
* @param pluginFilter
|
||||
*/
|
||||
void setPluginFilter(PluginFilter pluginFilter) { _pluginFilter = pluginFilter; }
|
||||
|
||||
/**
|
||||
* @brief Get a list of all the display plugins
|
||||
*
|
||||
* @return DisplayPluginList List of display plugins
|
||||
*/
|
||||
Q_INVOKABLE DisplayPluginList getAllDisplayPlugins();
|
||||
|
||||
bool getEnableOculusPluginSetting() { return _enableOculusPluginSetting.get(); }
|
||||
void setEnableOculusPluginSetting(bool value);
|
||||
|
||||
/**
|
||||
* @brief Returns information about known plugins
|
||||
*
|
||||
* This is a function for informative/debugging purposes.
|
||||
*
|
||||
* @return std::vector<PluginInfo>
|
||||
*/
|
||||
std::vector<PluginInfo> getPluginInfo() const;
|
||||
|
||||
signals:
|
||||
void inputDeviceRunningChanged(const QString& pluginName, bool isRunning, const QStringList& runningDevices);
|
||||
|
||||
|
||||
private:
|
||||
PluginManager() = default;
|
||||
|
||||
|
|
Loading…
Reference in a new issue