From 276835f74c91a6387e4b80207a68f24c21732e7c Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 21 Jan 2022 22:47:02 +0000 Subject: [PATCH] osgXR: Update to 0.3.8 Update 3rdparty/osgXR to version 0.3.8, which gets us non-linear sRGB swapchain formats by default. This avoids double gamma correction with Monado when FlightGear renders non-linear sRGB data into linear RGB swapchain images. --- 3rdparty/osgXR/CHANGELOG.md | 54 ++++++ 3rdparty/osgXR/CMakeLists.txt | 5 +- 3rdparty/osgXR/README.md | 2 +- 3rdparty/osgXR/include/osgXR/Settings | 195 +++++++++++++++++++- 3rdparty/osgXR/src/CMakeLists.txt | 15 +- 3rdparty/osgXR/src/Mirror.cpp | 2 + 3rdparty/osgXR/src/Settings.cpp | 22 +++ 3rdparty/osgXR/src/XRState.cpp | 246 +++++++++++++++++++++++--- 3rdparty/osgXR/src/XRState.h | 9 +- 9 files changed, 516 insertions(+), 34 deletions(-) diff --git a/3rdparty/osgXR/CHANGELOG.md b/3rdparty/osgXR/CHANGELOG.md index 2213a592a..eb77a79b5 100644 --- a/3rdparty/osgXR/CHANGELOG.md +++ b/3rdparty/osgXR/CHANGELOG.md @@ -1,3 +1,57 @@ +Version 0.3.8 +------------- + +Highlights: + * Swapchain format preferences, allowing more formats to be chosen, and using + sRGB formats by default. + * Handle building as a CMake subproject. + +New/expanded APIs: + * Settings::preferRGBEncoding(), Settings::allowRGBEncoding() - For choosing + preferred and allowed RGB encodings from linear, floating point (linear), and + sRGB (non-linear). + * Settings::preferDepthEncoding(), Settings::allowDepthEncoding() - For + choosing preferred and allowed depth encodings from linear, and floating + point. + * Settings::getRGBBits(), Settings::setRGBBits() - For choosing preferred + number of bits per RGB channel (for linear & float encodings only), + overriding the graphics window traits bit depths. + * Settings::getAlphaBits(), Settings::setAlphaBits() - For choosing preferred + number of alpha channel bits, overriding the graphics window traits bit + depths. + * Settings::getDepthBits(), Settings::setDepthBits() - For choosing preferred + number of depth channel bits, overriding the graphics window traits bit + depths. + * Settings::getStencilBits(), Settings::setStencilBits() - For choosing + preferred number of stencil channel bits, overriding the graphics window + traits bit depths. + * Settings::getPreferredRGBEncodingMask(), + Settings::setPreferredRGBEncodingMask(), + Settings::getAllowedRGBEncodingMask(), + Settings::setAllowedRGBEncodingMask() - Largely internal for directly + accessing the masks of preferred and allowed RGB encodings. + * Settings::getPreferredDepthEncodingMask(), + Settings::setPreferredDepthEncodingMask(), + Settings::getAllowedDepthEncodingMask(), + Settings::setAllowedDepthEncodingMask() - Largely internal for directly + accessing the masks of preferred and allowed depth encodings. + +Documentation: + * Settings: Tweak comment wording for consistency. + +Behaviour changes: + * Determine swapchain formats using new preferences specified in Settings, + using sRGB formats by default instead of linear. + * Choose a suitable depth/stencil fallback for when a depth swapchain cannot be + used. + * Enable gamma correction when rendering VR mirror to sRGB framebuffer. + +Build system: + * Handle building as a subproject. + * Reduce minimum CMake version to 3.11. + * Add OSGXR\_WARNINGS option to enable compiler warnings (for development use). + * Drop osgXR\_INCLUDE\_DIR use since newer CMake handles automatically. + Version 0.3.7 ------------- diff --git a/3rdparty/osgXR/CMakeLists.txt b/3rdparty/osgXR/CMakeLists.txt index 87862f2e3..e20f6b272 100644 --- a/3rdparty/osgXR/CMakeLists.txt +++ b/3rdparty/osgXR/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.11) set(osgXR_MAJOR_VERSION 0) set(osgXR_MINOR_VERSION 3) -set(osgXR_PATCH_VERSION 7) -set(osgXR_SOVERSION 5) +set(osgXR_PATCH_VERSION 8) +set(osgXR_SOVERSION 6) set(osgXR_VERSION "${osgXR_MAJOR_VERSION}.${osgXR_MINOR_VERSION}.${osgXR_PATCH_VERSION}") @@ -22,6 +22,7 @@ if(CMAKE_PROJECT_NAME STREQUAL osgXR) # Build options option(BUILD_SHARED_LIBS "Whether to build as a shared library" ON) option(BUILD_OSGXR_EXAMPLES "Enable to build osgXR examples" OFF) + option(OSGXR_WARNINGS "Enable compiler warnings for osgXR" OFF) # Source files in src/ add_subdirectory(src) diff --git a/3rdparty/osgXR/README.md b/3rdparty/osgXR/README.md index 61b802ba3..8be669a1d 100644 --- a/3rdparty/osgXR/README.md +++ b/3rdparty/osgXR/README.md @@ -41,7 +41,7 @@ Getting Started To import osgXR into a CMake based project, you can use the included CMake module, adding something like this to your CMakeLists.txt: ```cmake -find_package(osgXR 0.3.5 REQUIRED) +find_package(osgXR 0.3.8 REQUIRED) target_link_libraries(target .. diff --git a/3rdparty/osgXR/include/osgXR/Settings b/3rdparty/osgXR/include/osgXR/Settings index a413492f9..244a1adaf 100644 --- a/3rdparty/osgXR/include/osgXR/Settings +++ b/3rdparty/osgXR/include/osgXR/Settings @@ -171,7 +171,7 @@ class OSGXR_EXPORT Settings : public osg::Referenced } BlendMode; /** * Specify a preferred environment blend mode. - * The chosen environment blend mode is permitted for use, and will be + * The chosen environment blend mode is allowed for use, and will be * chosen in preference to any other supported environment blend modes * specified by allowEnvBlendMode() if supported by OpenXR. * @param mode Environment blend mode to prefer. @@ -183,8 +183,8 @@ class OSGXR_EXPORT Settings : public osg::Referenced _allowedEnvBlendModeMask |= mask; } /** - * Specify a permitted environment blend mode. - * The chosen environment blend mode is permitted for use, and may be + * Specify an allowed environment blend mode. + * The chosen environment blend mode is allowed for use, and may be * chosen if supported by OpenXR when none of the preferred environment * blend modes specified by preferEnvBlenMode() are supported by OpenXR. * @param mode Environment blend mode to prefer. @@ -204,7 +204,7 @@ class OSGXR_EXPORT Settings : public osg::Referenced { _preferredEnvBlendModeMask = preferredEnvBlendModeMask; } - /// Get the bitmask of permitted environment blend modes. + /// Get the bitmask of allowed environment blend modes. uint32_t getAllowedEnvBlendModeMask() const { return _allowedEnvBlendModeMask; @@ -264,6 +264,172 @@ class OSGXR_EXPORT Settings : public osg::Referenced return _swapchainMode; } + /// RGB(A) / depth encodings. + typedef enum Encoding + { + /** Discrete linear encoding of RGB(A). + * The OpenXR runtime may perform its own conversion from RGB to + * sRGB for display on HMD, so the app should ensure it leaves RGB + * values linear to avoid an over-bright image. + */ + ENCODING_LINEAR = 0, + /** Floating-point linear encoding of RGB(A). + * The OpenXR runtime may perform its own conversion from RGB to + * sRGB for display on HMD, so the app should ensure it leaves RGB + * values linear to avoid an over-bright image. + */ + ENCODING_FLOAT = 1, + /** Discrete non-linear sRGB encoding with linear (A). + * Linear RGB values should be converted to sRGB, for example with + * GL_FRAMEBUFFER_SRGB or via fragment shader code, as the OpenXR + * runtime will treat them as non-linear. + * Not applicable to depth/stencil swapchains. + */ + ENCODING_SRGB = 2, + } Encoding; + + /** + * Specify a preferred RGB(A) encoding. + * The chosen RGB(A) encoding is allowed for use, and a format with this + * encoding will be chosen in preference to other allowed encodings + * specified by allowRGBEncoding() if possible. + * @param encoding RGB(A) encoding to prefer. + */ + void preferRGBEncoding(Encoding encoding) + { + uint32_t mask = (1u << (unsigned int)encoding); + _preferredRGBEncodingMask |= mask; + _allowedRGBEncodingMask |= mask; + } + /** + * Specify an allowed RGB(A) encoding. + * The chosen RGB(A) encoding is allowed for use, and a format with this + * encoding may be chosen when none of the preferred color encodings + * specified by preferRGBEncoding() are useable. + * @param encoding RGB(A) encoding to permit. + */ + void allowRGBEncoding(Encoding encoding) + { + uint32_t mask = (1u << (unsigned int)encoding); + _allowedRGBEncodingMask |= mask; + } + /// Get the bitmask of preferred RGB(A) encodings. + uint32_t getPreferredRGBEncodingMask() const + { + return _preferredRGBEncodingMask; + } + /// Set the bitmask of preferred RGB(A) encodings. + void setPreferredRGBEncodingMask(uint32_t preferredRGBEncodingMask) + { + _preferredRGBEncodingMask = preferredRGBEncodingMask; + } + /// Get the bitmask of allowed RGB(A) encodings. + uint32_t getAllowedRGBEncodingMask() const + { + return _allowedRGBEncodingMask; + } + /// Set the bitmask of allowed RGB(A) encodings. + void setAllowedRGBEncodingMask(uint32_t allowedRGBEncodingMask) + { + _allowedRGBEncodingMask = allowedRGBEncodingMask; + } + + /** + * Specify a preferred depth encoding. + * The chosen depth encoding is allowed for use, and a format with this + * encoding will be chosen in preference to other allowed encodings + * specified by allowDepthEncoding() if possible. + * @param encoding Depth encoding to prefer. + */ + void preferDepthEncoding(Encoding encoding) + { + uint32_t mask = (1u << (unsigned int)encoding); + _preferredDepthEncodingMask |= mask; + _allowedDepthEncodingMask |= mask; + } + /** + * Specify an allowed depth encoding. + * The chosen depth encoding is allowed for use, and a format with this + * encoding may be chosen when none of the preferred color encodings + * specified by preferDepthEncoding() are useable. + * @param encoding Depth encoding to permit. + */ + void allowDepthEncoding(Encoding encoding) + { + uint32_t mask = (1u << (unsigned int)encoding); + _allowedDepthEncodingMask |= mask; + } + /// Get the bitmask of preferred depth encodings. + uint32_t getPreferredDepthEncodingMask() const + { + return _preferredDepthEncodingMask; + } + /// Set the bitmask of preferred depth encodings. + void setPreferredDepthEncodingMask(uint32_t preferredDepthEncodingMask) + { + _preferredDepthEncodingMask = preferredDepthEncodingMask; + } + /// Get the bitmask of allowed depth encodings. + uint32_t getAllowedDepthEncodingMask() const + { + return _allowedDepthEncodingMask; + } + /// Set the bitmask of allowed depth encodings. + void setAllowedDepthEncodingMask(uint32_t allowedDepthEncodingMask) + { + _allowedDepthEncodingMask = allowedDepthEncodingMask; + } + + /** + * Get number of desired bits for each RGB channel in RGB(A) swapchain. + * This only applies to linear RGB formats, not sRGB formats. + */ + int getRGBBits() const + { + return _rgbBits; + } + /** + * Set number of desired bits for each RGB channel in RGB(A) swapchain. + * This only applies to linear RGB formats, not sRGB formats. + */ + void setRGBBits(int rgbBits = -1) + { + _rgbBits = rgbBits; + } + + /// Get number of desired alpha bits in RGB(A) swapchain. + int getAlphaBits() const + { + return _alphaBits; + } + /// Set the number of desired alpha bits in RGB(A) swapchain. + void setAlphaBits(int alphaBits = -1) + { + _alphaBits = alphaBits; + } + + /// Get number of desired depth bits in depth/stencil swapchain. + int getDepthBits() const + { + return _depthBits; + } + /// Set the number of desired depth bits in depth/stencil swapchain. + void setDepthBits(int depthBits = -1) + { + _depthBits = depthBits; + } + + /// Get number of desired stencil bits in depth/stencil swapchain. + int getStencilBits() const + { + return _stencilBits; + } + /// Set the number of desired stenil bits in depth/stencil swapchain. + void setStencilBits(int stencilBits = -1) + { + _stencilBits = stencilBits; + } + /// Get mirror settings. MirrorSettings &getMirrorSettings() { @@ -303,8 +469,14 @@ class OSGXR_EXPORT Settings : public osg::Referenced DIFF_BLEND_MODE = (1u << 5), DIFF_VR_MODE = (1u << 6), DIFF_SWAPCHAIN_MODE = (1u << 7), - DIFF_MIRROR = (1u << 8), - DIFF_SCALE = (1u << 9), + DIFF_RGB_ENCODING = (1u << 8), + DIFF_DEPTH_ENCODING = (1u << 9), + DIFF_RGB_BITS = (1u << 10), + DIFF_ALPHA_BITS = (1u << 11), + DIFF_DEPTH_BITS = (1u << 12), + DIFF_STENCIL_BITS = (1u << 13), + DIFF_MIRROR = (1u << 14), + DIFF_SCALE = (1u << 15), } _ChangeMask; unsigned int _diff(const Settings &other) const; @@ -333,6 +505,17 @@ class OSGXR_EXPORT Settings : public osg::Referenced VRMode _vrMode; SwapchainMode _swapchainMode; + // Swapchain requirements + uint32_t _preferredRGBEncodingMask; + uint32_t _allowedRGBEncodingMask; + uint32_t _preferredDepthEncodingMask; + uint32_t _allowedDepthEncodingMask; + // These default to -1: get bit depths from graphics window traits + int _rgbBits; // for linear RGB formats, per channel + int _alphaBits; + int _depthBits; + int _stencilBits; + // Mirror settings MirrorSettings _mirrorSettings; diff --git a/3rdparty/osgXR/src/CMakeLists.txt b/3rdparty/osgXR/src/CMakeLists.txt index f434a7ec7..76444ff0c 100644 --- a/3rdparty/osgXR/src/CMakeLists.txt +++ b/3rdparty/osgXR/src/CMakeLists.txt @@ -97,7 +97,20 @@ target_compile_features(osgXR # smart pointers PUBLIC cxx_std_11 # std::optional - PRIVATE cxx_std_17) + PRIVATE cxx_std_17 +) + +# Enable compiler warnings +if(OSGXR_WARNINGS) + target_compile_options(osgXR PRIVATE + $<$,$,$>: + -Wall -pedantic + -Wextra -Wno-missing-field-initializers + -Wno-unused-parameter> + $<$: + /W4> + ) +endif() target_include_directories(osgXR PRIVATE diff --git a/3rdparty/osgXR/src/Mirror.cpp b/3rdparty/osgXR/src/Mirror.cpp index a7249dfe0..f5425369f 100644 --- a/3rdparty/osgXR/src/Mirror.cpp +++ b/3rdparty/osgXR/src/Mirror.cpp @@ -127,8 +127,10 @@ void Mirror::setupQuad(unsigned int viewIndex, osg::ref_ptr state = quad->getOrCreateStateSet(); int forceOff = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED; + int forceOn = osg::StateAttribute::ON | osg::StateAttribute::PROTECTED; state->setMode(GL_LIGHTING, forceOff); state->setMode(GL_DEPTH_TEST, forceOff); + state->setMode(GL_FRAMEBUFFER_SRGB, forceOn); _camera->addChild(quad); diff --git a/3rdparty/osgXR/src/Settings.cpp b/3rdparty/osgXR/src/Settings.cpp index 5b56096d9..8353252cd 100644 --- a/3rdparty/osgXR/src/Settings.cpp +++ b/3rdparty/osgXR/src/Settings.cpp @@ -20,6 +20,14 @@ Settings::Settings() : _allowedEnvBlendModeMask(0), _vrMode(VRMODE_AUTOMATIC), _swapchainMode(SWAPCHAIN_AUTOMATIC), + _preferredRGBEncodingMask(0), + _allowedRGBEncodingMask(0), + _preferredDepthEncodingMask(0), + _allowedDepthEncodingMask(0), + _rgbBits(-1), + _alphaBits(-1), + _depthBits(-1), + _stencilBits(-1), _unitsPerMeter(1.0f) { } @@ -55,6 +63,20 @@ unsigned int Settings::_diff(const Settings &other) const ret |= DIFF_VR_MODE; if (_swapchainMode != other._swapchainMode) ret |= DIFF_SWAPCHAIN_MODE; + if (_preferredRGBEncodingMask != other._preferredRGBEncodingMask || + _allowedRGBEncodingMask != other._allowedRGBEncodingMask) + ret |= DIFF_RGB_ENCODING; + if (_preferredDepthEncodingMask != other._preferredDepthEncodingMask || + _allowedDepthEncodingMask != other._allowedDepthEncodingMask) + ret |= DIFF_DEPTH_ENCODING; + if (_rgbBits != other._rgbBits) + ret |= DIFF_RGB_BITS; + if (_alphaBits != other._alphaBits) + ret |= DIFF_ALPHA_BITS; + if (_depthBits != other._depthBits) + ret |= DIFF_DEPTH_BITS; + if (_stencilBits != other._stencilBits) + ret |= DIFF_STENCIL_BITS; if (_mirrorSettings != other._mirrorSettings) ret |= DIFF_MIRROR; if (_unitsPerMeter != other._unitsPerMeter) diff --git a/3rdparty/osgXR/src/XRState.cpp b/3rdparty/osgXR/src/XRState.cpp index 5beda9e5a..6925a1c4e 100644 --- a/3rdparty/osgXR/src/XRState.cpp +++ b/3rdparty/osgXR/src/XRState.cpp @@ -62,7 +62,8 @@ XRState::XRSwapchain::XRSwapchain(XRState *state, osg::ref_ptr session, const OpenXR::System::ViewConfiguration::View &view, int64_t chosenSwapchainFormat, - int64_t chosenDepthSwapchainFormat) : + int64_t chosenDepthSwapchainFormat, + GLenum fallbackDepthFormat) : OpenXR::SwapchainGroup(session, view, XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, chosenSwapchainFormat, @@ -95,6 +96,7 @@ XRState::XRSwapchain::XRSwapchain(XRState *state, XRFramebuffer *fb = new XRFramebuffer(getWidth(), getHeight(), texture, depthTexture); + fb->setDepthFormat(fallbackDepthFormat); _imageFramebuffers.push_back(fb); } } @@ -518,7 +520,13 @@ void XRState::syncSettings() else if (diff & (Settings::DIFF_DEPTH_INFO | Settings::DIFF_VISIBILITY_MASK | Settings::DIFF_VR_MODE | - Settings::DIFF_SWAPCHAIN_MODE)) + Settings::DIFF_SWAPCHAIN_MODE | + Settings::DIFF_RGB_ENCODING | + Settings::DIFF_DEPTH_ENCODING | + Settings::DIFF_RGB_BITS | + Settings::DIFF_ALPHA_BITS | + Settings::DIFF_DEPTH_BITS | + Settings::DIFF_STENCIL_BITS)) // Recreate session setDownState(VRSTATE_SYSTEM); } @@ -952,6 +960,14 @@ XRState::UpResult XRState::upSession() _settingsCopy.setVisibilityMask(_settings->getVisibilityMask()); _settingsCopy.setVRMode(_settings->getVRMode()); _settingsCopy.setSwapchainMode(_settings->getSwapchainMode()); + _settingsCopy.setPreferredRGBEncodingMask(_settings->getPreferredRGBEncodingMask()); + _settingsCopy.setAllowedRGBEncodingMask(_settings->getAllowedRGBEncodingMask()); + _settingsCopy.setPreferredDepthEncodingMask(_settings->getPreferredDepthEncodingMask()); + _settingsCopy.setAllowedDepthEncodingMask(_settings->getAllowedDepthEncodingMask()); + _settingsCopy.setRGBBits(_settings->getRGBBits()); + _settingsCopy.setAlphaBits(_settings->getAlphaBits()); + _settingsCopy.setDepthBits(_settings->getDepthBits()); + _settingsCopy.setStencilBits(_settings->getStencilBits()); _useDepthInfo = _settingsCopy.getDepthInfo(); _useVisibilityMask = _settingsCopy.getVisibilityMask(); _vrMode = _settingsCopy.getVRMode(); @@ -967,6 +983,31 @@ XRState::UpResult XRState::upSession() OSG_WARN << "osgXR: VisibilityMask extension not supported, visibility masking will be disabled" << std::endl; _useVisibilityMask = false; } + if (_settingsCopy.getAllowedRGBEncodingMask() == 0) + { + // Play safe and default to preferring sRGB over linear/float RGB, since + // this is what apps are normally tuned for. This avoids incorrect + // behaviour in SteamVR (no gamma correction) and also correct but + // potentially unexpected behaviour in Monado (extra gamma correction of + // linear RGB framebuffer when app produces sRGBish images already). + _settingsCopy.allowRGBEncoding(Settings::ENCODING_SRGB); + } + if (_settingsCopy.getPreferredRGBEncodingMask() == 0) + { + // If no preferred RGB encodings, mark all allowed ones as preferred. + _settingsCopy.setPreferredRGBEncodingMask(_settingsCopy.getAllowedRGBEncodingMask()); + } + if (_settingsCopy.getAllowedDepthEncodingMask() == 0) + { + // Default to allowing both discrete or floating point depth. + _settingsCopy.allowDepthEncoding(Settings::ENCODING_LINEAR); + _settingsCopy.allowDepthEncoding(Settings::ENCODING_FLOAT); + } + if (_settingsCopy.getPreferredDepthEncodingMask() == 0) + { + // If no preferred depth encodings, mark all allowed ones as preferred. + _settingsCopy.setPreferredDepthEncodingMask(_settingsCopy.getAllowedDepthEncodingMask()); + } // Decide on the algorithm to use. SceneView mode is faster. if (_vrMode == VRMode::VRMODE_AUTOMATIC) @@ -1009,52 +1050,209 @@ XRState::UpResult XRState::upSession() return UP_ABORT; } - // Decide on ideal depth bits - unsigned int bestDepthBits = 24; + // Decide on ideal bit depths + unsigned int bestRGBBits = 24; // combined + unsigned int bestAlphaBits = 0; + unsigned int bestDepthBits = 16; + unsigned int bestStencilBits = 0; + // Use graphics window traits auto *traits = _window->getTraits(); if (traits) + { + bestRGBBits = traits->red + traits->green + traits->blue; + bestAlphaBits = traits->alpha; bestDepthBits = traits->depth; + bestStencilBits = traits->stencil; + } + // Override from osgXR::Settings + if (_settingsCopy.getRGBBits() >= 0) + bestRGBBits = _settingsCopy.getRGBBits() * 3; + if (_settingsCopy.getAlphaBits() >= 0) + bestAlphaBits = _settingsCopy.getAlphaBits(); + if (_settingsCopy.getDepthBits() >= 0) + bestDepthBits = _settingsCopy.getDepthBits(); + if (_settingsCopy.getStencilBits() >= 0) + bestStencilBits = _settingsCopy.getStencilBits(); + + // Choose a fallback depth format in case we can't submit depth to OpenXR + GLenum fallbackDepthFormat = 0; + if (_settingsCopy.getPreferredDepthEncodingMask() & + (1u << (unsigned int)Settings::ENCODING_LINEAR)) + { + bool allowFloatDepth = _settingsCopy.getAllowedDepthEncodingMask() & + (1u << (unsigned int)Settings::ENCODING_FLOAT); + if (bestDepthBits > 24 && allowFloatDepth) + fallbackDepthFormat = bestStencilBits ? GL_DEPTH32F_STENCIL8 + : GL_DEPTH_COMPONENT32F; + else if (bestStencilBits) + fallbackDepthFormat = GL_DEPTH24_STENCIL8; + else if (bestDepthBits > 16) + fallbackDepthFormat = GL_DEPTH_COMPONENT24; + else + fallbackDepthFormat = GL_DEPTH_COMPONENT16; + } + else // getPreferredDepthEncodingMask & (1 << ENCODING_FLOAT) + { + if (bestStencilBits) + fallbackDepthFormat = GL_DEPTH32F_STENCIL8; + else + fallbackDepthFormat = GL_DEPTH_COMPONENT32F; + } // Choose a swapchain format int64_t chosenSwapchainFormat = 0; int64_t chosenDepthSwapchainFormat = 0; + unsigned int chosenAlphaBits = 0; unsigned int chosenDepthBits = 0; + unsigned int chosenStencilBits = 0; + uint32_t chosenRGBSat = 0; + uint32_t chosenDepthSat = 0; for (int64_t format: _session->getSwapchainFormats()) { + auto thisEncoding = Settings::ENCODING_LINEAR; + uint32_t encodingMask = 0; + unsigned int thisRGBBits = 0; + unsigned int thisAlphaBits = 0; unsigned int thisDepthBits = 0; + unsigned int thisStencilBits = 0; + unsigned int thisSat = 0; switch (format) { + // Discrete linear RGB(A) case GL_RGBA16: + thisRGBBits = 16 * 3; + thisAlphaBits = 16; + goto handleRGBA; case GL_RGB10_A2: + thisRGBBits = 10 * 3; + thisAlphaBits = 2; + goto handleRGBA; case GL_RGBA8: - // Choose the first supported format suggested by the runtime - if (!chosenSwapchainFormat) - chosenSwapchainFormat = format; - break; + thisRGBBits = 8 * 3; + thisAlphaBits = 8; + goto handleRGBA; + // Linear floating point RGB(A) + case GL_RGB16F: + thisRGBBits = 16 * 3; + thisEncoding = Settings::ENCODING_FLOAT; + goto handleRGBA; + case GL_RGBA16F: + thisRGBBits = 16 * 3; + thisEncoding = Settings::ENCODING_FLOAT; + thisAlphaBits = 16; + goto handleRGBA; + // Discrete sRGB (linear A) + case GL_SRGB8_ALPHA8: + thisEncoding = Settings::ENCODING_SRGB; + thisAlphaBits = 8; + goto handleRGBA; + case GL_SRGB8: + thisEncoding = Settings::ENCODING_SRGB; + goto handleRGBA; + + // Discrete depth (stencil) case GL_DEPTH_COMPONENT16: thisDepthBits = 16; - goto handle_depth; + goto handleDepth; case GL_DEPTH_COMPONENT24: thisDepthBits = 24; - goto handle_depth; + goto handleDepth; +#if 0 // crashes nvidia (495.46, with monado) + case GL_DEPTH24_STENCIL8: + thisDepthBits = 24; + thisStencilBits = 8; + goto handleDepth; +#endif case GL_DEPTH_COMPONENT32: thisDepthBits = 32; - // fall through - handle_depth: + goto handleDepth; + // Floating point depth, discrete stencil + case GL_DEPTH_COMPONENT32F: + thisEncoding = Settings::ENCODING_FLOAT; + thisDepthBits = 32; + goto handleDepth; + case GL_DEPTH32F_STENCIL8: + thisEncoding = Settings::ENCODING_FLOAT; + thisDepthBits = 32; + thisStencilBits = 8; + goto handleDepth; + + handleRGBA: + // Don't even consider a disallowed RGB encoding + encodingMask = (1u << (unsigned int)thisEncoding); + if (!(_settingsCopy.getAllowedRGBEncodingMask() & encodingMask)) + break; + + // Consider whether our preferences are satisfied + if (_settingsCopy.getPreferredRGBEncodingMask() & encodingMask) + thisSat |= 0x1; + if (thisEncoding == Settings::ENCODING_SRGB || thisRGBBits >= bestRGBBits) + thisSat |= 0x2; + if (thisAlphaBits >= bestAlphaBits) + thisSat |= 0x4; + + // Skip formats that no longer satisfies some preference + if (chosenRGBSat & ~thisSat) + break; + + // Decide whether to choose this format + if (// Anything is better than nothing + !chosenSwapchainFormat || + // New preferences satisfied is always better + (~chosenRGBSat & thisSat) || + // All else being equal, allow improved alpha bits + // A higher number of alpha bits is better than not enough + (thisAlphaBits > chosenAlphaBits && chosenAlphaBits < bestAlphaBits)) + { + chosenSwapchainFormat = format; + chosenAlphaBits = thisAlphaBits; + chosenRGBSat = thisSat; + } + break; + + handleDepth: if (_useDepthInfo) { + // Don't even consider a disallowed depth encoding + encodingMask = (1u << (unsigned int)thisEncoding); + if (!(_settingsCopy.getAllowedDepthEncodingMask() & encodingMask)) + break; + + // Consider whether our preferences are satisfied + if (_settingsCopy.getPreferredDepthEncodingMask() & encodingMask) + thisSat |= 0x1; + if (thisDepthBits >= bestDepthBits) + thisSat |= 0x2; + if (thisStencilBits >= bestStencilBits) + thisSat |= 0x4; + + // Skip formats that no longer satisfies some preference + if (chosenDepthSat & ~thisSat) + break; + if (// Anything is better than nothing !chosenDepthSwapchainFormat || - // A higher number of bits is better than not enough + // New preferences satisfied is always better + (~chosenRGBSat & thisSat) || + // A higher number of depth bits is better than not enough (thisDepthBits > chosenDepthBits && chosenDepthBits < bestDepthBits) || - // A lower number of bits may still be enough - (bestDepthBits < thisDepthBits && thisDepthBits < chosenDepthBits)) + // A higher number of stencil bits is better than not enough + // so long as depth bits are no worse or good enough + ((thisDepthBits >= chosenDepthBits || thisDepthBits >= bestDepthBits) && + thisStencilBits > chosenStencilBits && chosenStencilBits < bestStencilBits) || + // A lower number of depth bits may still be enough + // so long as stencil bits are no worse or good enough + ((thisStencilBits >= chosenStencilBits || thisStencilBits >= bestStencilBits) && + bestDepthBits < thisDepthBits && thisDepthBits < chosenDepthBits)) { chosenDepthSwapchainFormat = format; chosenDepthBits = thisDepthBits; + chosenStencilBits = thisStencilBits; + chosenDepthSat = thisSat; } } break; + default: break; } @@ -1086,7 +1284,8 @@ XRState::UpResult XRState::upSession() { case SwapchainMode::SWAPCHAIN_SINGLE: if (!setupSingleSwapchain(chosenSwapchainFormat, - chosenDepthSwapchainFormat)) + chosenDepthSwapchainFormat, + fallbackDepthFormat)) { _session = nullptr; return UP_ABORT; @@ -1097,7 +1296,8 @@ XRState::UpResult XRState::upSession() // Should already have been handled by upSession() case SwapchainMode::SWAPCHAIN_MULTIPLE: if (!setupMultipleSwapchains(chosenSwapchainFormat, - chosenDepthSwapchainFormat)) + chosenDepthSwapchainFormat, + fallbackDepthFormat)) { _session = nullptr; return UP_ABORT; @@ -1172,7 +1372,8 @@ XRState::DownResult XRState::downActions() return DOWN_SUCCESS; } -bool XRState::setupSingleSwapchain(int64_t format, int64_t depthFormat) +bool XRState::setupSingleSwapchain(int64_t format, int64_t depthFormat, + GLenum fallbackDepthFormat) { const auto &views = _chosenViewConfig->getViews(); _xrViews.reserve(views.size()); @@ -1187,7 +1388,8 @@ bool XRState::setupSingleSwapchain(int64_t format, int64_t depthFormat) // Create a single swapchain osg::ref_ptr xrSwapchain = new XRSwapchain(this, _session, singleView, format, - depthFormat); + depthFormat, + fallbackDepthFormat); // And the views _xrViews.reserve(views.size()); for (uint32_t i = 0; i < views.size(); ++i) @@ -1205,7 +1407,8 @@ bool XRState::setupSingleSwapchain(int64_t format, int64_t depthFormat) return true; } -bool XRState::setupMultipleSwapchains(int64_t format, int64_t depthFormat) +bool XRState::setupMultipleSwapchains(int64_t format, int64_t depthFormat, + GLenum fallbackDepthFormat) { const auto &views = _chosenViewConfig->getViews(); _xrViews.reserve(views.size()); @@ -1215,7 +1418,8 @@ bool XRState::setupMultipleSwapchains(int64_t format, int64_t depthFormat) const auto &vcView = views[i]; osg::ref_ptr xrSwapchain = new XRSwapchain(this, _session, vcView, format, - depthFormat); + depthFormat, + fallbackDepthFormat); osg::ref_ptr xrView = new XRView(this, i, xrSwapchain); if (!xrView.valid()) { diff --git a/3rdparty/osgXR/src/XRState.h b/3rdparty/osgXR/src/XRState.h index 65cdbd83d..db00148f2 100644 --- a/3rdparty/osgXR/src/XRState.h +++ b/3rdparty/osgXR/src/XRState.h @@ -62,7 +62,8 @@ class XRState : public OpenXR::EventHandler osg::ref_ptr session, const OpenXR::System::ViewConfiguration::View &view, int64_t chosenSwapchainFormat, - int64_t chosenDepthSwapchainFormat); + int64_t chosenDepthSwapchainFormat, + GLenum fallbackDepthFormat); // GL context must be current (for XRFramebuffer) virtual ~XRSwapchain(); @@ -502,9 +503,11 @@ class XRState : public OpenXR::EventHandler DownResult downActions(); // Set up a single swapchain containing multiple viewports - bool setupSingleSwapchain(int64_t format, int64_t depthFormat = 0); + bool setupSingleSwapchain(int64_t format, int64_t depthFormat = 0, + GLenum fallbackDepthFormat = 0); // Set up a swapchain for each view - bool setupMultipleSwapchains(int64_t format, int64_t depthFormat = 0); + bool setupMultipleSwapchains(int64_t format, int64_t depthFormat = 0, + GLenum fallbackDepthFormat = 0); // Set up slave cameras void setupSlaveCameras(); // Set up SceneView VR mode cameras