From fe066069d79bd5e7e419373fd8d801792befc857 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sun, 25 Sep 2022 21:19:03 +0200 Subject: [PATCH] /components/ code should not access the stereo manager without checking whether or not stereo is enabled first. Stereo component code should not read settings itself, but rather take settings as parameters. --- apps/openmw/engine.cpp | 52 ++++++++++++++++- apps/openmw/mwrender/pingpongcanvas.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwrender/transparentpass.cpp | 2 +- apps/openmw/mwrender/water.cpp | 2 +- components/sceneutil/rtt.cpp | 13 +++-- components/sceneutil/shadow.cpp | 7 ++- components/sceneutil/statesetupdater.cpp | 9 +-- components/shader/shadervisitor.cpp | 2 +- components/stereo/multiview.cpp | 25 +++++---- components/stereo/multiview.hpp | 4 +- components/stereo/stereomanager.cpp | 71 +++++------------------- components/stereo/stereomanager.hpp | 31 +++++++++-- components/terrain/material.cpp | 2 +- 14 files changed, 130 insertions(+), 94 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3b90f60a0b..f00c40017e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -155,7 +155,51 @@ namespace void operator()(osg::GraphicsContext* graphicsContext) override { - Stereo::Manager::instance().initializeStereo(graphicsContext); + auto& sm = Stereo::Manager::instance(); + + if (Settings::Manager::getBool("use custom view", "Stereo")) + { + Stereo::View left; + Stereo::View right; + + left.pose.position.x() = Settings::Manager::getDouble("left eye offset x", "Stereo View"); + left.pose.position.y() = Settings::Manager::getDouble("left eye offset y", "Stereo View"); + left.pose.position.z() = Settings::Manager::getDouble("left eye offset z", "Stereo View"); + left.pose.orientation.x() = Settings::Manager::getDouble("left eye orientation x", "Stereo View"); + left.pose.orientation.y() = Settings::Manager::getDouble("left eye orientation y", "Stereo View"); + left.pose.orientation.z() = Settings::Manager::getDouble("left eye orientation z", "Stereo View"); + left.pose.orientation.w() = Settings::Manager::getDouble("left eye orientation w", "Stereo View"); + left.fov.angleLeft = Settings::Manager::getDouble("left eye fov left", "Stereo View"); + left.fov.angleRight = Settings::Manager::getDouble("left eye fov right", "Stereo View"); + left.fov.angleUp = Settings::Manager::getDouble("left eye fov up", "Stereo View"); + left.fov.angleDown = Settings::Manager::getDouble("left eye fov down", "Stereo View"); + + right.pose.position.x() = Settings::Manager::getDouble("right eye offset x", "Stereo View"); + right.pose.position.y() = Settings::Manager::getDouble("right eye offset y", "Stereo View"); + right.pose.position.z() = Settings::Manager::getDouble("right eye offset z", "Stereo View"); + right.pose.orientation.x() = Settings::Manager::getDouble("right eye orientation x", "Stereo View"); + right.pose.orientation.y() = Settings::Manager::getDouble("right eye orientation y", "Stereo View"); + right.pose.orientation.z() = Settings::Manager::getDouble("right eye orientation z", "Stereo View"); + right.pose.orientation.w() = Settings::Manager::getDouble("right eye orientation w", "Stereo View"); + right.fov.angleLeft = Settings::Manager::getDouble("right eye fov left", "Stereo View"); + right.fov.angleRight = Settings::Manager::getDouble("right eye fov right", "Stereo View"); + right.fov.angleUp = Settings::Manager::getDouble("right eye fov up", "Stereo View"); + right.fov.angleDown = Settings::Manager::getDouble("right eye fov down", "Stereo View"); + + auto customViewCallback = std::make_shared(left, right); + sm.setUpdateViewCallback(customViewCallback); + } + + if (Settings::Manager::getBool("use custom eye resolution", "Stereo")) + { + osg::Vec2i eyeResolution = osg::Vec2i(); + eyeResolution.x() = Settings::Manager::getInt("eye resolution x", "Stereo View"); + eyeResolution.y() = Settings::Manager::getInt("eye resolution y", "Stereo View"); + sm.overrideEyeResolution(eyeResolution); + } + + sm.initializeStereo( + graphicsContext, Settings::Manager::getBool("multiview", "Stereo")); } }; } @@ -610,7 +654,7 @@ void OMW::Engine::createWindow() if (Stereo::getStereo()) { realizeOperations->add(new InitializeStereoOperation()); - Stereo::setVertexBufferHint(); + Stereo::setVertexBufferHint(Settings::Manager::getBool("multiview", "Stereo")); } mViewer->realize(); @@ -650,7 +694,9 @@ void OMW::Engine::prepareEngine() mStateManager = std::make_unique(mCfgMgr.getUserDataPath() / "saves", mContentFiles); mEnvironment.setStateManager(*mStateManager); - mStereoManager = std::make_unique(mViewer); + bool stereoEnabled + = Settings::Manager::getBool("stereo enabled", "Stereo") || osg::DisplaySettings::instance().get()->getStereo(); + mStereoManager = std::make_unique(mViewer, stereoEnabled); osg::ref_ptr rootNode(new osg::Group); mViewer->setSceneData(rootNode); diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index ef3f3fb67f..6a56f7e5f7 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -30,7 +30,7 @@ namespace MWRender mLuminanceCalculator.disable(); Shader::ShaderManager::DefineMap defines; - Stereo::Manager::instance().shaderStereoDefines(defines); + Stereo::shaderStereoDefines(defines); mFallbackProgram = shaderManager.getProgram("fullscreen_tri"); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 06c40b13ec..27478f0571 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -365,7 +365,7 @@ namespace MWRender if (mSceneManager->getForceShaders()) { Shader::ShaderManager::DefineMap defines = {}; - Stereo::Manager::instance().shaderStereoDefines(defines); + Stereo::shaderStereoDefines(defines); auto program = mSceneManager->getShaderManager().getProgram("sky", defines); mEarlyRenderBinRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("pass", -1)); mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes( diff --git a/apps/openmw/mwrender/transparentpass.cpp b/apps/openmw/mwrender/transparentpass.cpp index a2cbb54ed3..a0736b650b 100644 --- a/apps/openmw/mwrender/transparentpass.cpp +++ b/apps/openmw/mwrender/transparentpass.cpp @@ -33,7 +33,7 @@ namespace MWRender mStateSet->setTextureAttributeAndModes(0, dummyTexture); Shader::ShaderManager::DefineMap defines; - Stereo::Manager::instance().shaderStereoDefines(defines); + Stereo::shaderStereoDefines(defines); mStateSet->setAttributeAndModes(new osg::BlendFunc, modeOff); mStateSet->setAttributeAndModes(shaderManager.getProgram("depthclipped", defines), modeOn); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 5c57764c80..a96ff2966a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -695,7 +695,7 @@ namespace MWRender defineMap["ripple_map_world_scale"] = std::to_string(RipplesSurface::mWorldScaleFactor); defineMap["ripple_map_size"] = std::to_string(RipplesSurface::mRTTSize) + ".0"; - Stereo::Manager::instance().shaderStereoDefines(defineMap); + Stereo::shaderStereoDefines(defineMap); Shader::ShaderManager& shaderMgr = mResourceSystem->getSceneManager()->getShaderManager(); osg::ref_ptr program = shaderMgr.getProgram("water", defineMap); diff --git a/components/sceneutil/rtt.cpp b/components/sceneutil/rtt.cpp index c855784aa4..eec4aaa35d 100644 --- a/components/sceneutil/rtt.cpp +++ b/components/sceneutil/rtt.cpp @@ -54,11 +54,14 @@ namespace SceneUtil if (frameNumber > vdd->mFrameNumber) { apply(vdd->mCamera); - auto& sm = Stereo::Manager::instance(); - if (sm.getEye(cv) == Stereo::Eye::Left) - applyLeft(vdd->mCamera); - if (sm.getEye(cv) == Stereo::Eye::Right) - applyRight(vdd->mCamera); + if (Stereo::getStereo()) + { + auto& sm = Stereo::Manager::instance(); + if (sm.getEye(cv) == Stereo::Eye::Left) + applyLeft(vdd->mCamera); + if (sm.getEye(cv) == Stereo::Eye::Right) + applyRight(vdd->mCamera); + } vdd->mCamera->accept(*cv); } vdd->mFrameNumber = frameNumber; diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 7fe7363a74..4cf8a89255 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -115,7 +115,9 @@ namespace SceneUtil , mIndoorShadowCastingMask(indoorShadowCastingMask) { mShadowedScene->setShadowTechnique(mShadowTechnique); - Stereo::Manager::instance().setShadowTechnique(mShadowTechnique); + + if (Stereo::getStereo()) + Stereo::Manager::instance().setShadowTechnique(mShadowTechnique); mShadowedScene->addChild(sceneRoot); rootNode->addChild(mShadowedScene); @@ -132,7 +134,8 @@ namespace SceneUtil ShadowManager::~ShadowManager() { - Stereo::Manager::instance().setShadowTechnique(nullptr); + if (Stereo::getStereo()) + Stereo::Manager::instance().setShadowTechnique(nullptr); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 89017e628b..42dab1cc98 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -42,12 +42,13 @@ namespace SceneUtil { auto stateset = getCvDependentStateset(cv); apply(stateset, cv); - auto* sm = &Stereo::Manager::instance(); - if (sm != nullptr) + + if (Stereo::getStereo()) { - if (sm->getEye(cv) == Stereo::Eye::Left) + auto& sm = Stereo::Manager::instance(); + if (sm.getEye(cv) == Stereo::Eye::Left) applyLeft(stateset, cv); - if (sm->getEye(cv) == Stereo::Eye::Right) + if (sm.getEye(cv) == Stereo::Eye::Right) applyRight(stateset, cv); } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 69e91f057a..c9f9dc08fe 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -711,7 +711,7 @@ namespace Shader defineMap["softParticles"] = reqs.mSoftParticles ? "1" : "0"; - Stereo::Manager::instance().shaderStereoDefines(defineMap); + Stereo::shaderStereoDefines(defineMap); std::string shaderPrefix; if (!node.getUserValue("shaderPrefix", shaderPrefix)) diff --git a/components/stereo/multiview.cpp b/components/stereo/multiview.cpp index e3bcb7b479..5111870c2b 100644 --- a/components/stereo/multiview.cpp +++ b/components/stereo/multiview.cpp @@ -74,12 +74,6 @@ namespace Stereo return false; } - if (!Settings::Manager::getBool("multiview", "Stereo")) - { - Log(Debug::Verbose) << "Disabling Multiview (disabled by config)"; - return false; - } - if (!getMultiviewSupported(contextID)) { return false; @@ -95,6 +89,8 @@ namespace Stereo return true; } + static bool sMultiview = false; + bool getMultiview(unsigned int contextID) { static bool multiView = getMultiviewImpl(contextID); @@ -112,16 +108,25 @@ namespace Stereo return getMultiview(0); } - void configureExtensions(unsigned int contextID) + void configureExtensions(unsigned int contextID, bool enableMultiview) { getTextureViewSupported(contextID); getMultiviewSupported(contextID); - getMultiview(contextID); + + if (enableMultiview) + { + sMultiview = getMultiview(contextID); + } + else + { + Log(Debug::Verbose) << "Disabling Multiview (disabled by config)"; + sMultiview = false; + } } - void setVertexBufferHint() + void setVertexBufferHint(bool enableMultiview) { - if (getStereo() && Settings::Manager::getBool("multiview", "Stereo")) + if (getStereo() && enableMultiview) { auto* ds = osg::DisplaySettings::instance().get(); if (!Settings::Manager::getBool("allow display lists for multiview", "Stereo") diff --git a/components/stereo/multiview.hpp b/components/stereo/multiview.hpp index 2c82666262..fa69afc7a1 100644 --- a/components/stereo/multiview.hpp +++ b/components/stereo/multiview.hpp @@ -34,10 +34,10 @@ namespace Stereo //! Use the provided context to check what extensions are supported and configure use of multiview based on //! extensions and settings. - void configureExtensions(unsigned int contextID); + void configureExtensions(unsigned int contextID, bool enableMultiview); //! Sets the appropriate vertex buffer hint on OSG's display settings if needed - void setVertexBufferHint(); + void setVertexBufferHint(bool enableMultiview); //! Creates a Texture2D as a texture view into a Texture2DArray osg::ref_ptr createTextureView_Texture2DFromTexture2DArray( diff --git a/components/stereo/stereomanager.cpp b/components/stereo/stereomanager.cpp index 348e287d8e..261a24422f 100644 --- a/components/stereo/stereomanager.cpp +++ b/components/stereo/stereomanager.cpp @@ -105,6 +105,8 @@ namespace Stereo Manager* mManager; }; + static bool sStereoEnabled = false; + static Manager* sInstance = nullptr; Manager& Manager::instance() @@ -112,19 +114,7 @@ namespace Stereo return *sInstance; } - struct CustomViewCallback : public Manager::UpdateViewCallback - { - public: - CustomViewCallback(); - - void updateView(View& left, View& right) override; - - private: - View mLeft; - View mRight; - }; - - Manager::Manager(osgViewer::Viewer* viewer) + Manager::Manager(osgViewer::Viewer* viewer, bool enableStereo) : mViewer(viewer) , mMainCamera(mViewer->getCamera()) , mUpdateCallback(new StereoUpdateCallback(this)) @@ -137,29 +127,19 @@ namespace Stereo if (sInstance) throw std::logic_error("Double instance of Stereo::Manager"); sInstance = this; - - if (Settings::Manager::getBool("use custom view", "Stereo")) - mUpdateViewCallback = std::make_shared(); - - if (Settings::Manager::getBool("use custom eye resolution", "Stereo")) - { - osg::Vec2i eyeResolution = osg::Vec2i(); - eyeResolution.x() = Settings::Manager::getInt("eye resolution x", "Stereo View"); - eyeResolution.y() = Settings::Manager::getInt("eye resolution y", "Stereo View"); - overrideEyeResolution(eyeResolution); - } + sStereoEnabled = enableStereo; } Manager::~Manager() {} - void Manager::initializeStereo(osg::GraphicsContext* gc) + void Manager::initializeStereo(osg::GraphicsContext* gc, bool enableMultiview) { + auto ci = gc->getState()->getContextID(); + configureExtensions(ci, enableMultiview); + mMainCamera->addUpdateCallback(mUpdateCallback); mFrustumManager = std::make_unique(mViewer->getCamera()); - auto ci = gc->getState()->getContextID(); - configureExtensions(ci); - if (getMultiview()) setupOVRMultiView2Technique(); else @@ -168,7 +148,7 @@ namespace Stereo updateStereoFramebuffer(); } - void Manager::shaderStereoDefines(Shader::ShaderManager::DefineMap& defines) const + void shaderStereoDefines(Shader::ShaderManager::DefineMap& defines) { if (getMultiview()) { @@ -402,39 +382,16 @@ namespace Stereo bool getStereo() { - static bool stereo = Settings::Manager::getBool("stereo enabled", "Stereo") - || osg::DisplaySettings::instance().get()->getStereo(); - return stereo; + return sStereoEnabled; } - CustomViewCallback::CustomViewCallback() + Manager::CustomViewCallback::CustomViewCallback(View left, View right) + : mLeft(left) + , mRight(right) { - mLeft.pose.position.x() = Settings::Manager::getDouble("left eye offset x", "Stereo View"); - mLeft.pose.position.y() = Settings::Manager::getDouble("left eye offset y", "Stereo View"); - mLeft.pose.position.z() = Settings::Manager::getDouble("left eye offset z", "Stereo View"); - mLeft.pose.orientation.x() = Settings::Manager::getDouble("left eye orientation x", "Stereo View"); - mLeft.pose.orientation.y() = Settings::Manager::getDouble("left eye orientation y", "Stereo View"); - mLeft.pose.orientation.z() = Settings::Manager::getDouble("left eye orientation z", "Stereo View"); - mLeft.pose.orientation.w() = Settings::Manager::getDouble("left eye orientation w", "Stereo View"); - mLeft.fov.angleLeft = Settings::Manager::getDouble("left eye fov left", "Stereo View"); - mLeft.fov.angleRight = Settings::Manager::getDouble("left eye fov right", "Stereo View"); - mLeft.fov.angleUp = Settings::Manager::getDouble("left eye fov up", "Stereo View"); - mLeft.fov.angleDown = Settings::Manager::getDouble("left eye fov down", "Stereo View"); - - mRight.pose.position.x() = Settings::Manager::getDouble("right eye offset x", "Stereo View"); - mRight.pose.position.y() = Settings::Manager::getDouble("right eye offset y", "Stereo View"); - mRight.pose.position.z() = Settings::Manager::getDouble("right eye offset z", "Stereo View"); - mRight.pose.orientation.x() = Settings::Manager::getDouble("right eye orientation x", "Stereo View"); - mRight.pose.orientation.y() = Settings::Manager::getDouble("right eye orientation y", "Stereo View"); - mRight.pose.orientation.z() = Settings::Manager::getDouble("right eye orientation z", "Stereo View"); - mRight.pose.orientation.w() = Settings::Manager::getDouble("right eye orientation w", "Stereo View"); - mRight.fov.angleLeft = Settings::Manager::getDouble("right eye fov left", "Stereo View"); - mRight.fov.angleRight = Settings::Manager::getDouble("right eye fov right", "Stereo View"); - mRight.fov.angleUp = Settings::Manager::getDouble("right eye fov up", "Stereo View"); - mRight.fov.angleDown = Settings::Manager::getDouble("right eye fov down", "Stereo View"); } - void CustomViewCallback::updateView(View& left, View& right) + void Manager::CustomViewCallback::updateView(View& left, View& right) { left = mLeft; right = mRight; diff --git a/components/stereo/stereomanager.hpp b/components/stereo/stereomanager.hpp index 53f8e00740..c047859b54 100644 --- a/components/stereo/stereomanager.hpp +++ b/components/stereo/stereomanager.hpp @@ -39,6 +39,9 @@ namespace Stereo bool getStereo(); + //! Sets up any definitions necessary for stereo rendering + void shaderStereoDefines(Shader::ShaderManager::DefineMap& defines); + //! Class that provides tools for managing stereo mode class Manager { @@ -51,16 +54,37 @@ namespace Stereo virtual void updateView(View& left, View& right) = 0; }; + //! An UpdateViewCallback that supplies a fixed, custom view. Useful for debugging purposes, + //! such as emulating a given HMD's view. + struct CustomViewCallback : public UpdateViewCallback + { + public: + CustomViewCallback(View left, View right); + + void updateView(View& left, View& right) override; + + private: + View mLeft; + View mRight; + }; + //! Gets the singleton instance static Manager& instance(); - Manager(osgViewer::Viewer* viewer); + //! Constructor + //! + //! @Param viewer the osg viewer whose stereo should be managed. + //! @Param enableStereo whether or not stereo should be enabled. + //! @Param enableMultiview whether or not to make use of the GL_OVR_Multiview extension, if supported. + Manager(osgViewer::Viewer* viewer, bool enableStereo); ~Manager(); //! Called during update traversal void update(); - void initializeStereo(osg::GraphicsContext* gc); + //! Initializes all details of stereo if applicable. If the constructor was called with enableMultiview=true, + //! and the GL_OVR_Multiview extension is supported, Stereo::getMultiview() will return true after this call. + void initializeStereo(osg::GraphicsContext* gc, bool enableMultiview); //! Callback that updates stereo configuration during the update pass void setUpdateViewCallback(std::shared_ptr cb); @@ -71,9 +95,6 @@ namespace Stereo osg::Matrixd computeEyeProjection(int view, bool reverseZ) const; osg::Matrixd computeEyeViewOffset(int view) const; - //! Sets up any definitions necessary for stereo rendering - void shaderStereoDefines(Shader::ShaderManager::DefineMap& defines) const; - const std::shared_ptr& multiviewFramebuffer() { return mMultiviewFramebuffer; } //! Sets rendering resolution of each eye to eyeResolution. diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index c06735d927..fafe2dcb58 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -283,7 +283,7 @@ namespace Terrain defineMap["specularMap"] = it->mSpecular ? "1" : "0"; defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0"; defineMap["writeNormals"] = (it == layers.end() - 1) ? "1" : "0"; - Stereo::Manager::instance().shaderStereoDefines(defineMap); + Stereo::shaderStereoDefines(defineMap); stateset->setAttributeAndModes(shaderManager.getProgram("terrain", defineMap)); stateset->addUniform(UniformCollection::value().mColorMode);