diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2f5f0ef5d..748642937 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1023,12 +1023,7 @@ void OMW::Engine::go() } else { - mViewer->eventTraversal(); - mViewer->updateTraversal(); - - mEnvironment.getWorld()->updateWindowManager(); - - mViewer->renderingTraversals(); + mEnvironment.getWindowManager()->viewerTraversals(true); bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); if (!guiActive) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 07405b11f..de6451cd8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -350,6 +350,8 @@ namespace MWBase virtual void watchActor(const MWWorld::Ptr& ptr) = 0; virtual MWWorld::Ptr getWatchedActor() const = 0; + + virtual void viewerTraversals(bool updateWindowManager) = 0; }; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7ddc8c550..9c76ff2c3 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -407,9 +407,7 @@ namespace MWGui // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + MWBase::Environment::get().getWindowManager()->viewerTraversals(false); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); if (mHasCallback) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6aeb9123f..1d282d5e3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -124,6 +124,8 @@ #include "../mwvr/vrenvironment.hpp" #include "../mwvr/vrgui.hpp" #include "../mwvr/vrvirtualkeyboard.hpp" +#include "../mwvr/vrviewer.hpp" +#include "../mwvr/vrsession.hpp" #endif namespace MWGui @@ -770,11 +772,7 @@ namespace MWGui if (!mWindowVisible) std::this_thread::sleep_for(std::chrono::milliseconds(5)); else - { - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); - } + viewerTraversals(false); // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() @@ -1829,9 +1827,7 @@ namespace MWGui if (mVideoWidget->isPaused()) mVideoWidget->resume(); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + viewerTraversals(false); } // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. @@ -2248,6 +2244,25 @@ namespace MWGui return MyGUI::InputManager::getInstance().injectKeyRelease(key); } + void WindowManager::viewerTraversals(bool updateWindowManager) + { +#ifdef USE_OPENXR + if (MWBase::Environment::get().getVrMode()) + MWVR::Environment::get().getSession()->beginFrame(); +#endif + + mViewer->eventTraversal(); + mViewer->updateTraversal(); + if (updateWindowManager) + MWBase::Environment::get().getWorld()->updateWindowManager(); + mViewer->renderingTraversals(); + +#ifdef USE_OPENXR + if (MWBase::Environment::get().getVrMode()) + MWVR::Environment::get().getSession()->endFrame(); +#endif + } + void WindowManager::GuiModeState::update(bool visible) { for (unsigned int i=0; igetLoadingScreen()->loadingOn(false); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + MWBase::Environment::get().getWindowManager()->viewerTraversals(false); callback->waitTillDone(); MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOff(); @@ -969,9 +967,6 @@ namespace MWRender void RenderingManager::screenshotFramebuffer(osg::Image* image, int w, int h) { osg::Camera* camera = mViewer->getCamera(); -#ifdef USE_OPENXR - MWVR::Environment::get().getSession()->beginPhase(MWVR::VRSession::FramePhase::Update); -#endif osg::ref_ptr tempDrw = new osg::Drawable; tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h)); tempDrw->setCullingActive(false); @@ -980,9 +975,7 @@ namespace MWRender osg::ref_ptr callback (new NotifyDrawCompletedCallback(mViewer->getFrameStamp()->getFrameNumber())); auto* oldCb = camera->getFinalDrawCallback(); camera->setFinalDrawCallback(callback); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + MWBase::Environment::get().getWindowManager()->viewerTraversals(false); callback->waitTillDone(); // now that we've "used up" the current frame, get a fresh frame number for the next frame() following after the screenshot is completed mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); diff --git a/apps/openmw/mwvr/vrinputmanager.cpp b/apps/openmw/mwvr/vrinputmanager.cpp index 3acf452e5..7f4765edf 100644 --- a/apps/openmw/mwvr/vrinputmanager.cpp +++ b/apps/openmw/mwvr/vrinputmanager.cpp @@ -394,12 +394,13 @@ namespace MWVR updateActivationIndication(); MWInput::InputManager::update(dt, disableControls, disableEvents); + // This is the first update that needs openxr tracking, so i begin the next frame here. auto* session = Environment::get().getSession(); if (!session) return; - session->beginPhase(VRSession::FramePhase::Update); + session->beginFrame(); // The rest of this code assumes the game is running if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) diff --git a/apps/openmw/mwvr/vrsession.cpp b/apps/openmw/mwvr/vrsession.cpp index a3c3bc352..b99f60ddc 100644 --- a/apps/openmw/mwvr/vrsession.cpp +++ b/apps/openmw/mwvr/vrsession.cpp @@ -78,6 +78,26 @@ namespace MWVR } } + void VRSession::beginFrame() + { + // Viewer traversals are sometimes entered without first updating the input manager. + if (getFrame(FramePhase::Update) == nullptr) + { + beginPhase(FramePhase::Update); + } + + } + + void VRSession::endFrame() + { + // Make sure we don't continue until the render thread has moved the frame to its next phase. + std::unique_lock lock(mMutex); + while (getFrame(FramePhase::Update)) + { + mCondition.wait(lock); + } + } + osg::Matrix VRSession::viewMatrix(osg::Vec3 position, osg::Quat orientation) { position = position * Constants::UnitsPerMeter; @@ -179,7 +199,7 @@ namespace MWVR std::unique_lock lock(mMutex); while (getFrame(phase)) { - //Log(Debug::Verbose) << "Warning: beginPhase called with a frame already in the target phase"; + Log(Debug::Verbose) << "Warning: beginPhase called with a frame already in the target phase"; mCondition.wait(lock); } } diff --git a/apps/openmw/mwvr/vrsession.hpp b/apps/openmw/mwvr/vrsession.hpp index df6fe78d8..5ff8d7217 100644 --- a/apps/openmw/mwvr/vrsession.hpp +++ b/apps/openmw/mwvr/vrsession.hpp @@ -78,6 +78,9 @@ namespace MWVR void processChangedSettings(const std::set< std::pair >& changed); + void beginFrame(); + void endFrame(); + private: std::mutex mMutex{}; std::condition_variable mCondition{}; diff --git a/apps/openmw/mwvr/vrviewer.cpp b/apps/openmw/mwvr/vrviewer.cpp index 176072465..17b565b22 100644 --- a/apps/openmw/mwvr/vrviewer.cpp +++ b/apps/openmw/mwvr/vrviewer.cpp @@ -57,12 +57,6 @@ namespace MWVR { } - void VRViewer::traversals() - { - mViewer->updateTraversal(); - mViewer->renderingTraversals(); - } - int parseResolution(std::string conf, int recommended, int max) { if (Misc::StringUtils::isNumber(conf)) diff --git a/apps/openmw/mwvr/vrviewer.hpp b/apps/openmw/mwvr/vrviewer.hpp index 964931fc8..1e0adc0c9 100644 --- a/apps/openmw/mwvr/vrviewer.hpp +++ b/apps/openmw/mwvr/vrviewer.hpp @@ -104,7 +104,6 @@ namespace MWVR ~VRViewer(void); - void traversals(); void swapBuffersCallback(osg::GraphicsContext* gc); void initialDrawCallback(osg::RenderInfo& info); void preDrawCallback(osg::RenderInfo& info);