From 89ff07593660e0f42997b9098a19339a88137c94 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Fri, 7 Aug 2020 23:33:21 +0200 Subject: [PATCH] New config options --- apps/openmw/mwvr/openxrmanagerimpl.cpp | 16 ++--- apps/openmw/mwvr/openxrswapchainimpl.cpp | 16 ++--- apps/openmw/mwvr/vrtypes.hpp | 15 +++-- apps/openmw/mwvr/vrviewer.cpp | 78 +++++++++++++++++++----- apps/openmw/mwvr/vrviewer.hpp | 2 +- components/misc/stringops.hpp | 13 ++++ files/settings-default.cfg | 15 ++++- 7 files changed, 112 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwvr/openxrmanagerimpl.cpp b/apps/openmw/mwvr/openxrmanagerimpl.cpp index 1a24dd18c..2220c173a 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.cpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.cpp @@ -346,7 +346,7 @@ namespace MWVR for (auto format : swapchainFormats) { - ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::endl; + ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::dec << std::endl; } Log(Debug::Verbose) << ss.str(); @@ -375,7 +375,7 @@ namespace MWVR auto error = glGetError(); while (error != GL_NO_ERROR) { - Log(Debug::Warning) << "glGetError: " << std::dec << error << " (0x" << std::hex << error << ")"; + Log(Debug::Warning) << "glGetError: " << std::dec << error << " (0x" << std::hex << error << ")" << std::dec; } } @@ -745,12 +745,12 @@ namespace MWVR std::array config{}; for (uint32_t i = 0; i < 2; i++) config[i] = SwapchainConfig{ - mConfigViews[i].recommendedImageRectWidth, - mConfigViews[i].maxImageRectWidth, - mConfigViews[i].recommendedImageRectHeight, - mConfigViews[i].maxImageRectHeight, - mConfigViews[i].recommendedSwapchainSampleCount, - mConfigViews[i].recommendedSwapchainSampleCount, + (int)mConfigViews[i].recommendedImageRectWidth, + (int)mConfigViews[i].recommendedImageRectHeight, + (int)mConfigViews[i].recommendedSwapchainSampleCount, + (int)mConfigViews[i].maxImageRectWidth, + (int)mConfigViews[i].maxImageRectHeight, + (int)mConfigViews[i].maxSwapchainSampleCount, }; return config; } diff --git a/apps/openmw/mwvr/openxrswapchainimpl.cpp b/apps/openmw/mwvr/openxrswapchainimpl.cpp index 13126ead9..900cfd94e 100644 --- a/apps/openmw/mwvr/openxrswapchainimpl.cpp +++ b/apps/openmw/mwvr/openxrswapchainimpl.cpp @@ -13,9 +13,9 @@ namespace MWVR { OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr state, SwapchainConfig config) - : mWidth((int)config.recommendedWidth) - , mHeight((int)config.recommendedHeight) - , mSamples((int)config.recommendedSamples) + : mWidth(config.selectedWidth) + , mHeight(config.selectedHeight) + , mSamples(config.selectedSamples) { if (mWidth <= 0) throw std::invalid_argument("Width must be a positive integer"); @@ -48,7 +48,7 @@ namespace MWVR { throw std::runtime_error("Swapchain color format not supported"); } mSwapchainColorFormat = *swapchainFormatIt; - Log(Debug::Verbose) << "Selected color format: " << std::dec << mSwapchainColorFormat << " (" << std::hex << mSwapchainColorFormat << ")"; + Log(Debug::Verbose) << "Selected color format: " << std::dec << mSwapchainColorFormat << " (" << std::hex << mSwapchainColorFormat << ")" << std::dec; if (xr->xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME)) { @@ -69,16 +69,10 @@ namespace MWVR { { mSwapchainDepthFormat = *swapchainFormatIt; mHaveDepthSwapchain = true; - Log(Debug::Verbose) << "Selected depth format: " << std::dec << mSwapchainDepthFormat << " (" << std::hex << mSwapchainDepthFormat << ")"; + Log(Debug::Verbose) << "Selected depth format: " << std::dec << mSwapchainDepthFormat << " (" << std::hex << mSwapchainDepthFormat << ")" << std::dec; } } - mSamples = Settings::Manager::getInt("antialiasing", "Video"); - // OpenXR requires a non-zero value - if (mSamples < 1) - mSamples = 1; - - XrSwapchainCreateInfo swapchainCreateInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO }; swapchainCreateInfo.arraySize = 1; swapchainCreateInfo.width = mWidth; diff --git a/apps/openmw/mwvr/vrtypes.hpp b/apps/openmw/mwvr/vrtypes.hpp index f3416eff3..701b7caee 100644 --- a/apps/openmw/mwvr/vrtypes.hpp +++ b/apps/openmw/mwvr/vrtypes.hpp @@ -99,12 +99,15 @@ namespace MWVR struct SwapchainConfig { - uint32_t recommendedWidth = -1; - uint32_t maxWidth = -1; - uint32_t recommendedHeight = -1; - uint32_t maxHeight = -1; - uint32_t recommendedSamples = -1; - uint32_t maxSamples = -1; + int recommendedWidth = -1; + int recommendedHeight = -1; + int recommendedSamples = -1; + int maxWidth = -1; + int maxHeight = -1; + int maxSamples = -1; + int selectedWidth = -1; + int selectedHeight = -1; + int selectedSamples = -1; }; struct FrameInfo diff --git a/apps/openmw/mwvr/vrviewer.cpp b/apps/openmw/mwvr/vrviewer.cpp index bae9da7a6..bfd565255 100644 --- a/apps/openmw/mwvr/vrviewer.cpp +++ b/apps/openmw/mwvr/vrviewer.cpp @@ -12,6 +12,8 @@ #include +#include + namespace MWVR { @@ -52,6 +54,28 @@ namespace MWVR mViewer->renderingTraversals(); } + int parseResolution(std::string conf, int recommended, int max) + { + if (Misc::StringUtils::isNumber(conf)) + { + int res = std::atoi(conf.c_str()); + if (res <= 0) + return recommended; + if (res > max) + return max; + return res; + } + conf = Misc::StringUtils::lowerCase(conf); + if (conf == "auto" || conf == "recommended") + { + return recommended; + } + if (conf == "max") + { + return max; + } + } + void VRViewer::realize(osg::GraphicsContext* context) { std::unique_lock lock(mMutex); @@ -86,19 +110,49 @@ namespace MWVR osg::Vec4 clearColor = mainCamera->getClearColor(); auto config = xr->getRecommendedSwapchainConfig(); bool mirror = Settings::Manager::getBool("mirror texture", "VR"); - mFlipMirrorTextureOrder = Settings::Manager::getBool("flip mirror texture order", "VR"); + std::string mirrorTextureEyeString = Settings::Manager::getString("mirror texture eye", "VR"); + mirrorTextureEyeString = Misc::StringUtils::lowerCase(mirrorTextureEyeString); + if (mirrorTextureEyeString == "left" || mirrorTextureEyeString == "both") + mMirrorTextureViews.push_back(sViewNames[(int)Side::LEFT_SIDE]); + if (mirrorTextureEyeString == "right" || mirrorTextureEyeString == "both") + mMirrorTextureViews.push_back(sViewNames[(int)Side::RIGHT_SIDE]); + if (Settings::Manager::getBool("flip mirror texture order", "VR")) + std::reverse(mMirrorTextureViews.begin(), mMirrorTextureViews.end()); // TODO: If mirror is false either hide the window or paste something meaningful into it. // E.g. Fanart of Dagoth UR wearing a VR headset + std::array xConfString; + std::array yConfString; + xConfString[0] = Settings::Manager::getString("left eye resolution x", "VR"); + yConfString[0] = Settings::Manager::getString("left eye resolution y", "VR"); + + xConfString[1] = Settings::Manager::getString("right eye resolution x", "VR"); + yConfString[1] = Settings::Manager::getString("right eye resolution y", "VR"); + for (unsigned i = 0; i < sViewNames.size(); i++) { - auto view = new VRView(sViewNames[i], config[i], context->getState()); - mViews[sViewNames[i]] = view; - auto camera = mCameras[sViewNames[i]] = view->createCamera(i + 2, clearColor, context); + auto name = sViewNames[i]; + + config[i].selectedWidth = parseResolution(xConfString[i], config[i].recommendedWidth, config[i].maxWidth); + config[i].selectedHeight = parseResolution(yConfString[i], config[i].recommendedHeight, config[i].maxHeight); + + config[i].selectedSamples = Settings::Manager::getInt("antialiasing", "Video"); + // OpenXR requires a non-zero value + if (config[i].selectedSamples < 1) + config[i].selectedSamples = 1; + + Log(Debug::Verbose) << name << " resolution: Recommended x=" << config[i].recommendedWidth << ", y=" << config[i].recommendedHeight; + Log(Debug::Verbose) << name << " resolution: Max x=" << config[i].maxWidth << ", y=" << config[i].maxHeight; + Log(Debug::Verbose) << name << " resolution: Selected x=" << config[i].selectedWidth << ", y=" << config[i].selectedHeight; + + + auto view = new VRView(name, config[i], context->getState()); + mViews[name] = view; + auto camera = mCameras[name] = view->createCamera(i + 2, clearColor, context); camera->setPreDrawCallback(mPreDraw); camera->setFinalDrawCallback(mPostDraw); camera->setCullMask(~MWRender::Mask_GUI & ~MWRender::Mask_SimpleWater & ~MWRender::Mask_UpdateVisitor); - camera->setName(sViewNames[i]); + camera->setName(name); if (smallFeatureCulling) camera->setSmallFeatureCullingPixelSize(smallFeatureCullingPixelSize); camera->setCullingMode(cullingMode); @@ -154,22 +208,18 @@ namespace MWVR auto* gl = osg::GLExtensions::Get(state->getContextID(), false); int screenWidth = mCameras["MainCamera"]->getViewport()->width(); - int mirrorWidth = screenWidth / 2; + int mirrorWidth = screenWidth / mMirrorTextureViews.size(); int screenHeight = mCameras["MainCamera"]->getViewport()->height(); // Since OpenXR does not include native support for mirror textures, we have to generate them ourselves - // which means resolving msaa twice. If this is a performance concern, add an option to disable the mirror texture. - for (unsigned i = 0; i < sViewNames.size(); i++) + // which means resolving msaa twice. + for (unsigned i = 0; i < mMirrorTextureViews.size(); i++) { auto& resolveTexture = *mMsaaResolveMirrorTexture[i]; resolveTexture.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT); - mViews[sViewNames[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height()); + mViews[mMirrorTextureViews[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height()); mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT); - - unsigned mirrorIndex = i; - if (mFlipMirrorTextureOrder) - mirrorIndex = sViewNames.size() - 1 - i; - resolveTexture.blit(gc, mirrorIndex * mirrorWidth, 0, (mirrorIndex + 1) * mirrorWidth, screenHeight); + resolveTexture.blit(gc, i * mirrorWidth, 0, (i + 1) * mirrorWidth, screenHeight); } gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); diff --git a/apps/openmw/mwvr/vrviewer.hpp b/apps/openmw/mwvr/vrviewer.hpp index 8cca6e3d3..3bc7ce1ee 100644 --- a/apps/openmw/mwvr/vrviewer.hpp +++ b/apps/openmw/mwvr/vrviewer.hpp @@ -99,7 +99,7 @@ namespace MWVR std::mutex mMutex{}; bool mConfigured{ false }; - bool mFlipMirrorTextureOrder{ false }; + std::vector mMirrorTextureViews; }; } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index aa2ae105e..5d5acb4d4 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -164,6 +164,19 @@ public: return out; } + /// true if the string is a number + static bool isNumber(const std::string& in) + { + for (auto c : in) + { + if (!std::isdigit(c)) + { + return false; + } + } + return true; + } + struct CiComp { bool operator()(const std::string& left, const std::string& right) const diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 070a4f268..47676b2ae 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -909,6 +909,18 @@ real height = 1.85 # If enabled, the game window will show your VR view. If not, it will show nothing. mirror texture = true +# If mirror texture is enabled, what eye to pick. Must be 'left', 'right', or 'both'. +mirror texture eye = right + +# If true, draw left eye on the right and vice versa to allow cross-eyed view. +flip mirror texture order = false + +# Resolution of each eye. 'auto' or 'recommended' uses the resolution recommended by openxr. 'max' uses the greater available resolution. If a resolution greater than the maximum reported by openxr is selected, the max recommended by openxr is used instead. The recommended and maximum resolutions will be output in openmw.log during startup. +left eye resolution x = auto +left eye resolution y = auto +right eye resolution x = auto +right eye resolution y = auto + # Openmw will sync with openxr at the beginning of this phase in the rendering pipeline. From early to late in the pipeline the options are update, cull, draw, and swap in that order. If you experience visual glitches such as frames jittering across your vision, try changing this to an earlier phase. openxr sync phase = draw @@ -921,9 +933,6 @@ realistic combat maximum swing velocity = 4.0 # Enables controller vibrations when you hit or are hit. haptics enabled = true -# Flip the order of eyes in the mirror texture (to allow cross eyed view) -flip mirror texture order = false - # Work around for some preview openxr runtimes whose display time predictions do not work # Use this if tracking seems crazy. use steady clock = false