From a2a462f416b7c3c8b1f0c126833e2f101b9d5049 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Fri, 18 Dec 2020 20:04:24 +0000 Subject: [PATCH 1/5] Update CMakeLists.txt to disable MSVC warning 4866 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76764fbd9..f0f7a3fc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -557,6 +557,7 @@ if (WIN32) # caused by MyGUI 4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception' 4297 # function assumed not to throw an exception but does + 4866 # compiler may not enforce left-to-right evaluation order for call # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type From 637c76f438774eb691b1980ad1636f1918e889f5 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 19 Dec 2020 08:34:36 +0000 Subject: [PATCH 2/5] Update CMakeLists.txt --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0f7a3fc5..be7bc79e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -557,7 +557,6 @@ if (WIN32) # caused by MyGUI 4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception' 4297 # function assumed not to throw an exception but does - 4866 # compiler may not enforce left-to-right evaluation order for call # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type @@ -585,6 +584,12 @@ if (WIN32) 5031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file (config_begin.hpp, config_end.hpp) ) endif() + + if( "${MyGUI_VERSION}" VERSION_LESS_EQUAL "3.4.0" ) + set(WARNINGS_DISABLE ${WARNINGS_DISABLE} + 4866 # compiler may not enforce left-to-right evaluation order for call + ) + endif() foreach(d ${WARNINGS_DISABLE}) set(WARNINGS "${WARNINGS} /wd${d}") From 74806e48938efa9b84104c8e2a848205f6ecbe4d Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 19 Dec 2020 15:15:58 +0100 Subject: [PATCH 3/5] Better use of osg stereo, avoids redundant synchronization. --- apps/openmw/engine.cpp | 37 +++++---- components/misc/stereo.cpp | 159 +++++++++++++++++++++++-------------- components/misc/stereo.hpp | 10 ++- 3 files changed, 130 insertions(+), 76 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8c8e6458f..88bd5fda7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -663,19 +663,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) Settings::Manager::getInt("anisotropy", "General") ); - // geometry shader must be enabled before the RenderingManager sets up any shaders - // therefore this part is separate from the rest of stereo setup. - mStereoEnabled = Settings::Manager::getBool("stereo enabled", "Stereo"); - if (mStereoEnabled) - { - mResourceSystem->getSceneManager()->getShaderManager().setStereoGeometryShaderEnabled(Misc::getStereoTechnique() == Misc::StereoView::Technique::GeometryShader_IndexedViewports); - // Mask in everything that does not currently use shaders. - // Remove that altogether when the sky finally uses them. - auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles; - // Since shaders are not yet created, we need to use the brute force technique initially - mStereoView.reset(new Misc::StereoView(mViewer, Misc::StereoView::Technique::BruteForce, noShaderMask, MWRender::VisMask::Mask_Scene)); - } - int numThreads = Settings::Manager::getInt("preload num threads", "Cells"); if (numThreads <= 0) throw std::runtime_error("Invalid setting: 'preload num threads' must be >0"); @@ -734,6 +721,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); + + if (mStereoEnabled) + { + // Set up stereo + // Stereo setup is split in two because the GeometryShader approach cannot be used before the RenderingManager has been created. + // To be able to see the logo and initial loading screen the BruteForce technique must be set up here. + mStereoView->initializeStereo(mViewer, Misc::StereoView::Technique::BruteForce); + mResourceSystem->getSceneManager()->getShaderManager().setStereoGeometryShaderEnabled(Misc::getStereoTechnique() == Misc::StereoView::Technique::GeometryShader_IndexedViewports); + } + if (!mSkipMenu) { const std::string& logo = Fallback::Map::getString("Movies_Company_Logo"); @@ -747,9 +744,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string())); mEnvironment.getWorld()->setupPlayer(); - // Set up stereo if (mStereoEnabled) { + // Stereo shader technique can be set up now. mStereoView->setStereoTechnique(Misc::getStereoTechnique()); mStereoView->initializeScene(); mStereoView->setCullMask(mStereoView->getCullMask()); @@ -871,6 +868,18 @@ void OMW::Engine::go() // Create encoder mEncoder = new ToUTF8::Utf8Encoder(mEncoding); + // geometry shader must be enabled before the RenderingManager sets up any shaders + // therefore this part is separate from the rest of stereo setup. + mStereoEnabled = Settings::Manager::getBool("stereo enabled", "Stereo"); + if (mStereoEnabled) + { + // Mask in everything that does not currently use shaders. + // Remove that altogether when the sky finally uses them. + auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles; + // Since shaders are not yet created, we need to use the brute force technique initially + mStereoView.reset(new Misc::StereoView(noShaderMask, MWRender::VisMask::Mask_Scene)); + } + // Setup viewer mViewer = new osgViewer::Viewer; mViewer->setReleaseContextAtEndOfFrameHint(false); diff --git a/components/misc/stereo.cpp b/components/misc/stereo.cpp index a4b5bdf07..80056c136 100644 --- a/components/misc/stereo.cpp +++ b/components/misc/stereo.cpp @@ -6,6 +6,7 @@ #include +#include #include #include @@ -252,26 +253,20 @@ namespace Misc return camera; } - StereoView::StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask) - : mViewer(viewer) - , mMainCamera(mViewer->getCamera()) - , mRoot(mViewer->getSceneData()->asGroup()) + StereoView::StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask) + : mViewer(nullptr) + , mMainCamera(nullptr) + , mRoot(nullptr) , mStereoRoot(new osg::Group) , mUpdateCallback(new StereoUpdateCallback(this)) , mTechnique(Technique::None) , mNoShaderMask(noShaderMask) , mSceneMask(sceneMask) - , mCullMask(mMainCamera->getCullMask()) + , mCullMask(0) , mMasterConfig(new SharedShadowMapConfig) , mSlaveConfig(new SharedShadowMapConfig) , mSharedShadowMaps(Settings::Manager::getBool("shared shadow maps", "Stereo")) { - if (technique == Technique::None) - // Do nothing - return; - - mRoot->setDataVariance(osg::Object::STATIC); - mMasterConfig->_id = "STEREO"; mMasterConfig->_master = true; mSlaveConfig->_id = "STEREO"; @@ -283,42 +278,90 @@ namespace Misc mStereoRoot->addChild(mStereoBruteForceRoot); mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this)); - setStereoTechnique(technique); - if (sInstance) throw std::logic_error("Double instance og StereoView"); sInstance = this; + + auto* ds = osg::DisplaySettings::instance().get(); + ds->setStereo(true); + ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT); + ds->setUseSceneViewForStereoHint(true); } - void StereoView::setupBruteForceTechnique() + void StereoView::initializeStereo(osgViewer::Viewer* viewer, Technique technique) { - mLeftCamera = createCamera("Stereo Left", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mRightCamera = createCamera("Stereo Right", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mViewer = viewer; + mRoot = viewer->getSceneData()->asGroup(); + mMainCamera = viewer->getCamera(); + mCullMask = mMainCamera->getCullMask(); + + setStereoTechnique(technique); + } - if (mSharedShadowMaps) + void StereoView::initializeScene() + { + SceneUtil::FindByNameVisitor findScene("Scene Root"); + mRoot->accept(findScene); + mScene = findScene.mFoundNode; + if (!mScene) + throw std::logic_error("Couldn't find scene root"); + + if (mTechnique == Technique::GeometryShader_IndexedViewports) { - mLeftCamera->setUserData(mSlaveConfig); - mRightCamera->setUserData(mMasterConfig); + mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation. + mRightCamera->addChild(mScene); } + } - // Slave cameras must have their viewports defined immediately - auto width = mMainCamera->getViewport()->width(); - auto height = mMainCamera->getViewport()->height(); - mLeftCamera->setViewport(0, 0, width / 2, height); - mRightCamera->setViewport(width / 2, 0, width / 2, height); + void StereoView::setupBruteForceTechnique() + { + auto* ds = osg::DisplaySettings::instance().get(); + ds->setStereo(true); + ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT); + ds->setUseSceneViewForStereoHint(true); + + struct ComputeStereoMatricesCallback : public osgUtil::SceneView::ComputeStereoMatricesCallback + { + ComputeStereoMatricesCallback(StereoView* sv) + : mStereoView(sv) + { - // Threading should be stopped before adding new slave cameras - mViewer->stopThreading(); - mViewer->addSlave(mRightCamera, true); - mViewer->addSlave(mLeftCamera, true); - mRightCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); - mLeftCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + } - // Remove main camera's graphics context to ensure it does not do any work - mViewer->getCamera()->setGraphicsContext(nullptr); + osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const override + { + return mStereoView->computeLeftEyeProjection(projection); + } - // Re-realize to ensure slave cameras are set up with appropriate settings - mViewer->realize(); + osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const override + { + return mStereoView->computeLeftEyeView(view); + } + + osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const override + { + return mStereoView->computeRightEyeProjection(projection); + } + + osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const override + { + return mStereoView->computeRightEyeView(view); + } + + StereoView* mStereoView; + }; + + auto* renderer = static_cast(mMainCamera->getRenderer()); + + // osgViewer::Renderer always has two scene views + for (auto* sceneView : { renderer->getSceneView(0), renderer->getSceneView(1) }) + { + sceneView->setComputeStereoMatricesCallback(new ComputeStereoMatricesCallback(this)); + sceneView->getCullVisitorLeft()->setName("LEFT"); + sceneView->getCullVisitorRight()->setName("RIGHT"); + } + + mMainCamera->setUserData(mMasterConfig); } void StereoView::setupGeometryShaderIndexedViewportTechnique() @@ -338,7 +381,7 @@ namespace Misc for (unsigned int i = 0; i < viewer->getNumSlaves(); i++) { auto& slave = viewer->getSlave(i); - if (slave._camera == camera); + if (slave._camera == camera) { viewer->removeSlave(i); return; @@ -348,17 +391,10 @@ namespace Misc void StereoView::removeBruteForceTechnique() { - mViewer->stopThreading(); - removeSlave(mViewer, mRightCamera); - removeSlave(mViewer, mLeftCamera); - mLeftCamera->setUserData(nullptr); - mRightCamera->setUserData(nullptr); - - mMainCamera->setGraphicsContext(mRightCamera->getGraphicsContext()); - mLeftCamera = nullptr; - mRightCamera = nullptr; - - mViewer->realize(); + auto* ds = osg::DisplaySettings::instance().get(); + ds->setStereo(false); + if(mMainCamera->getUserData() == mMasterConfig) + mMainCamera->setUserData(nullptr); } void StereoView::removeGeometryShaderIndexedViewportTechnique() @@ -589,21 +625,6 @@ namespace Misc mUpdateViewCallback = cb; } - void StereoView::initializeScene() - { - SceneUtil::FindByNameVisitor findScene("Scene Root"); - mRoot->accept(findScene); - mScene = findScene.mFoundNode; - if (!mScene) - throw std::logic_error("Couldn't find scene root"); - - if (mTechnique == Technique::GeometryShader_IndexedViewports) - { - mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation. - mRightCamera->addChild(mScene); - } - } - void disableStereoForCamera(osg::Camera* camera) { auto* viewport = camera->getViewport(); @@ -735,4 +756,20 @@ namespace Misc { return mCullMask; } + osg::Matrixd StereoView::computeLeftEyeProjection(const osg::Matrixd& projection) const + { + return mLeftCamera->getProjectionMatrix(); + } + osg::Matrixd StereoView::computeLeftEyeView(const osg::Matrixd& view) const + { + return mLeftCamera->getViewMatrix(); + } + osg::Matrixd StereoView::computeRightEyeProjection(const osg::Matrixd& projection) const + { + return mRightCamera->getProjectionMatrix(); + } + osg::Matrixd StereoView::computeRightEyeView(const osg::Matrixd& view) const + { + return mRightCamera->getViewMatrix(); + } } diff --git a/components/misc/stereo.hpp b/components/misc/stereo.hpp index babac5bdb..21c8c9099 100644 --- a/components/misc/stereo.hpp +++ b/components/misc/stereo.hpp @@ -96,13 +96,14 @@ namespace Misc //! \param noShaderMask mask in all nodes that do not use shaders and must be rendered brute force. //! \param sceneMask must equal MWRender::VisMask::Mask_Scene. Necessary while VisMask is still not in components/ //! \note the masks apply only to the GeometryShader_IndexdViewports technique and can be 0 for the BruteForce technique. - StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask); + StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask); //! Updates uniforms with the view and projection matrices of each stereo view, and replaces the camera's view and projection matrix //! with a view and projection that closely envelopes the frustums of the two eyes. void update(); void updateStateset(osg::StateSet* stateset); + void initializeStereo(osgViewer::Viewer* viewer, Technique technique); //! Initialized scene. Call when the "scene root" node has been created void initializeScene(); @@ -129,6 +130,13 @@ namespace Misc //! Get the last applied cullmask. osg::Node::NodeMask getCullMask(); + + osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const; + osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const; + + osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const; + osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const; + private: void setupBruteForceTechnique(); void setupGeometryShaderIndexedViewportTechnique(); From 289a939d3b233c9558da4f28bb8c09f837642930 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 19 Dec 2020 15:47:16 +0100 Subject: [PATCH 4/5] Sharing shadow via cv instead --- components/misc/stereo.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/misc/stereo.cpp b/components/misc/stereo.cpp index 80056c136..5db0bad4c 100644 --- a/components/misc/stereo.cpp +++ b/components/misc/stereo.cpp @@ -357,11 +357,13 @@ namespace Misc for (auto* sceneView : { renderer->getSceneView(0), renderer->getSceneView(1) }) { sceneView->setComputeStereoMatricesCallback(new ComputeStereoMatricesCallback(this)); - sceneView->getCullVisitorLeft()->setName("LEFT"); - sceneView->getCullVisitorRight()->setName("RIGHT"); - } - mMainCamera->setUserData(mMasterConfig); + if (mSharedShadowMaps) + { + sceneView->getCullVisitorLeft()->setUserData(mMasterConfig); + sceneView->getCullVisitorRight()->setUserData(mSlaveConfig); + } + } } void StereoView::setupGeometryShaderIndexedViewportTechnique() From 434566ec806c0ddc99826a06b8d970cb7b8b2f32 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 19 Dec 2020 15:55:47 +0100 Subject: [PATCH 5/5] Allow sharing via cv instead of camera --- components/sceneutil/mwshadowtechnique.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index b1a01ac78..7367bdba3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -962,7 +962,9 @@ void SceneUtil::MWShadowTechnique::shareShadowMap(osgUtil::CullVisitor& cv, View bool MWShadowTechnique::trySharedShadowMap(osgUtil::CullVisitor& cv, ViewDependentData* vdd) { - auto* sharedConfig = dynamic_cast(cv.getCurrentCamera()->getUserData()); + auto* sharedConfig = dynamic_cast(cv.getUserData()); + if (!sharedConfig) + sharedConfig = dynamic_cast(cv.getCurrentCamera()->getUserData()); if (!sharedConfig) { return false; @@ -997,7 +999,9 @@ bool MWShadowTechnique::trySharedShadowMap(osgUtil::CullVisitor& cv, ViewDepende void SceneUtil::MWShadowTechnique::endSharedShadowMap(osgUtil::CullVisitor& cv) { - auto* sharedConfig = dynamic_cast(cv.getCurrentCamera()->getUserData()); + auto* sharedConfig = dynamic_cast(cv.getUserData()); + if (!sharedConfig) + sharedConfig = dynamic_cast(cv.getCurrentCamera()->getUserData()); if (!sharedConfig) { return;