From e3c460ae357df09b7ac36963823437b9bc8d6823 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 24 Jun 2020 22:22:09 +0200 Subject: [PATCH] Swapchain refactoring. Use of multisampling. Msaa resolve steps for mirror textures. --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwvr/openxrmanagerimpl.cpp | 1 + apps/openmw/mwvr/openxrswapchain.cpp | 176 +---------------------- apps/openmw/mwvr/openxrswapchain.hpp | 2 - apps/openmw/mwvr/openxrswapchainimpl.cpp | 152 ++++++++++++++++++++ apps/openmw/mwvr/openxrswapchainimpl.hpp | 50 +++++++ apps/openmw/mwvr/vrviewer.cpp | 31 +++- apps/openmw/mwvr/vrviewer.hpp | 2 + 8 files changed, 236 insertions(+), 180 deletions(-) create mode 100644 apps/openmw/mwvr/openxrswapchainimpl.cpp create mode 100644 apps/openmw/mwvr/openxrswapchainimpl.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0f144bd67..a01f99c29 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -132,6 +132,8 @@ if(BUILD_VR_OPENXR) mwvr/openxrmanagerimpl.cpp mwvr/openxrswapchain.hpp mwvr/openxrswapchain.cpp + mwvr/openxrswapchainimpl.hpp + mwvr/openxrswapchainimpl.cpp mwvr/realisticcombat.hpp mwvr/realisticcombat.cpp mwvr/vranimation.hpp diff --git a/apps/openmw/mwvr/openxrmanagerimpl.cpp b/apps/openmw/mwvr/openxrmanagerimpl.cpp index 9f0687f39..8f59f56ce 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.cpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.cpp @@ -1,4 +1,5 @@ #include "openxrmanagerimpl.hpp" +#include "openxrswapchain.hpp" #include "openxrswapchainimpl.hpp" #include "vrtexture.hpp" diff --git a/apps/openmw/mwvr/openxrswapchain.cpp b/apps/openmw/mwvr/openxrswapchain.cpp index be563f348..94a23ecd6 100644 --- a/apps/openmw/mwvr/openxrswapchain.cpp +++ b/apps/openmw/mwvr/openxrswapchain.cpp @@ -1,4 +1,5 @@ #include "openxrswapchain.hpp" +#include "openxrswapchainimpl.hpp" #include "openxrmanager.hpp" #include "openxrmanagerimpl.hpp" #include "vrenvironment.hpp" @@ -13,169 +14,6 @@ #include namespace MWVR { - - class OpenXRSwapchainImpl - { - public: - enum SubView - { - LEFT_VIEW = 0, - RIGHT_VIEW = 1, - SUBVIEW_MAX = RIGHT_VIEW, //!< Used to size subview arrays. Not a valid input. - }; - - OpenXRSwapchainImpl(osg::ref_ptr state, SwapchainConfig config); - ~OpenXRSwapchainImpl(); - - void beginFrame(osg::GraphicsContext* gc); - void endFrame(osg::GraphicsContext* gc); - void acquire(osg::GraphicsContext* gc); - void release(osg::GraphicsContext* gc); - - VRTexture* renderBuffer() const; - - uint32_t acquiredImage() const; - - bool isAcquired() const; - - XrSwapchain mSwapchain = XR_NULL_HANDLE; - std::vector mSwapchainImageBuffers{}; - //std::vector > mTextureBuffers{}; - XrSwapchainSubImage mSubImage{}; - int32_t mWidth = -1; - int32_t mHeight = -1; - int32_t mSamples = -1; - int64_t mSwapchainColorFormat = -1; - uint32_t mFBO = 0; - std::vector > mRenderBuffers{}; - int mRenderBuffer{ 0 }; - uint32_t mAcquiredImageIndex{ 0 }; - bool mIsAcquired{ false }; - }; - - OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr state, SwapchainConfig config) - : mWidth(config.recommendedWidth) - , mHeight(config.recommendedHeight) - , mSamples(config.recommendedSamples) - { - if (mWidth <= 0) - throw std::invalid_argument("Width must be a positive integer"); - if (mHeight <= 0) - throw std::invalid_argument("Height must be a positive integer"); - if (mSamples <= 0) - throw std::invalid_argument("Samples must be a positive integer"); - - auto* xr = Environment::get().getManager(); - - // Select a swapchain format. - uint32_t swapchainFormatCount; - CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), 0, &swapchainFormatCount, nullptr)); - std::vector swapchainFormats(swapchainFormatCount); - CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data())); - - // List of supported color swapchain formats. - constexpr int64_t SupportedColorSwapchainFormats[] = { - GL_RGBA8, - GL_RGBA8_SNORM, - }; - - auto swapchainFormatIt = - std::find_first_of(swapchainFormats.begin(), swapchainFormats.end(), std::begin(SupportedColorSwapchainFormats), - std::end(SupportedColorSwapchainFormats)); - if (swapchainFormatIt == swapchainFormats.end()) { - Log(Debug::Error) << "No swapchain format supported at runtime"; - } - - mSwapchainColorFormat = *swapchainFormatIt; - - Log(Debug::Verbose) << "Creating swapchain with dimensions Width=" << mWidth << " Heigh=" << mHeight << " SampleCount=" << mSamples; - - // Create the swapchain. - XrSwapchainCreateInfo swapchainCreateInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO }; - swapchainCreateInfo.arraySize = 1; - swapchainCreateInfo.format = mSwapchainColorFormat; - swapchainCreateInfo.width = mWidth; - swapchainCreateInfo.height = mHeight; - swapchainCreateInfo.mipCount = 1; - swapchainCreateInfo.faceCount = 1; - swapchainCreateInfo.sampleCount = mSamples; - swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; - CHECK_XRCMD(xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain)); - - uint32_t imageCount = 0; - CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr)); - - mSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR }); - CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast(mSwapchainImageBuffers.data()))); - //for (const auto& swapchainImage : mSwapchainImageBuffers) - // mTextureBuffers.push_back(new VRTexture(state, swapchainImage.image, mWidth, mHeight, 0)); - for (unsigned i = 0; i < imageCount; i++) - mRenderBuffers.emplace_back(new VRTexture(state, mWidth, mHeight, 0)); - - mSubImage.swapchain = mSwapchain; - mSubImage.imageRect.offset = { 0, 0 }; - mSubImage.imageRect.extent = { mWidth, mHeight }; - } - - OpenXRSwapchainImpl::~OpenXRSwapchainImpl() - { - if (mSwapchain) - CHECK_XRCMD(xrDestroySwapchain(mSwapchain)); - } - - VRTexture* OpenXRSwapchainImpl::renderBuffer() const - { - return mRenderBuffers[mRenderBuffer].get(); - } - - uint32_t OpenXRSwapchainImpl::acquiredImage() const - { - if(isAcquired()) - return mSwapchainImageBuffers[mAcquiredImageIndex].image; - throw std::logic_error("Swapbuffer not acquired before use"); - } - - bool OpenXRSwapchainImpl::isAcquired() const - { - return mIsAcquired; - } - - void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc) - { - mRenderBuffer = (mRenderBuffer + 1) % mRenderBuffers.size(); - renderBuffer()->beginFrame(gc); - } - - int swapCount = 0; - - void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc) - { - // Blit frame to swapchain - acquire(gc); - renderBuffer()->endFrame(gc, acquiredImage()); - release(gc); - } - - void OpenXRSwapchainImpl::acquire(osg::GraphicsContext* gc) - { - XrSwapchainImageAcquireInfo acquireInfo{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO }; - CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchain, &acquireInfo, &mAcquiredImageIndex)); - - XrSwapchainImageWaitInfo waitInfo{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; - waitInfo.timeout = XR_INFINITE_DURATION; - CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo)); - - mIsAcquired = true; - } - - void OpenXRSwapchainImpl::release(osg::GraphicsContext* gc) - { - mIsAcquired = false; - - XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO }; - CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo)); - } - OpenXRSwapchain::OpenXRSwapchain(osg::ref_ptr state, SwapchainConfig config) : mPrivate(new OpenXRSwapchainImpl(state, config)) { @@ -205,12 +43,6 @@ namespace MWVR { return impl().release(gc); } - const XrSwapchainSubImage& - OpenXRSwapchain::subImage(void) const - { - return impl().mSubImage; - } - uint32_t OpenXRSwapchain::acquiredImage() const { return impl().acquiredImage(); @@ -218,17 +50,17 @@ namespace MWVR { int OpenXRSwapchain::width() const { - return impl().mWidth; + return impl().width(); } int OpenXRSwapchain::height() const { - return impl().mHeight; + return impl().height(); } int OpenXRSwapchain::samples() const { - return impl().mSamples; + return impl().samples(); } bool OpenXRSwapchain::isAcquired() const diff --git a/apps/openmw/mwvr/openxrswapchain.hpp b/apps/openmw/mwvr/openxrswapchain.hpp index 73c4b305b..19ad119a6 100644 --- a/apps/openmw/mwvr/openxrswapchain.hpp +++ b/apps/openmw/mwvr/openxrswapchain.hpp @@ -33,8 +33,6 @@ namespace MWVR void acquire(osg::GraphicsContext* gc); //! Finalize render void release(osg::GraphicsContext* gc); - //! Get the view surface - const XrSwapchainSubImage& subImage(void) const; //! Currently acquired image uint32_t acquiredImage() const; //! Whether subchain is currently acquired (true) or released (false) diff --git a/apps/openmw/mwvr/openxrswapchainimpl.cpp b/apps/openmw/mwvr/openxrswapchainimpl.cpp new file mode 100644 index 000000000..2703641ea --- /dev/null +++ b/apps/openmw/mwvr/openxrswapchainimpl.cpp @@ -0,0 +1,152 @@ +#include "openxrswapchainimpl.hpp" +#include "vrenvironment.hpp" + +#include + +#include + +#include +#include +#include +#include + +namespace MWVR { + + + OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr state, SwapchainConfig config) + : mWidth((int)config.recommendedWidth) + , mHeight((int)config.recommendedHeight) + , mSamples((int)config.recommendedSamples) + { + if (mWidth <= 0) + throw std::invalid_argument("Width must be a positive integer"); + if (mHeight <= 0) + throw std::invalid_argument("Height must be a positive integer"); + if (mSamples <= 0) + throw std::invalid_argument("Samples must be a positive integer"); + + auto* xr = Environment::get().getManager(); + + // Select a swapchain format. + uint32_t swapchainFormatCount; + CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), 0, &swapchainFormatCount, nullptr)); + std::vector swapchainFormats(swapchainFormatCount); + CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data())); + + // List of supported color swapchain formats. + constexpr int64_t SupportedColorSwapchainFormats[] = { + GL_RGBA8, + GL_RGBA8_SNORM, + }; + + auto swapchainFormatIt = + std::find_first_of(swapchainFormats.begin(), swapchainFormats.end(), std::begin(SupportedColorSwapchainFormats), + std::end(SupportedColorSwapchainFormats)); + if (swapchainFormatIt == swapchainFormats.end()) { + Log(Debug::Error) << "No swapchain format supported at runtime"; + } + + mSwapchainColorFormat = *swapchainFormatIt; + + mSamples = Settings::Manager::getInt("antialiasing", "Video"); + + while (mSamples > 0) + { + Log(Debug::Verbose) << "Creating swapchain with dimensions Width=" << mWidth << " Heigh=" << mHeight << " SampleCount=" << mSamples; + // Create the swapchain. + XrSwapchainCreateInfo swapchainCreateInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO }; + swapchainCreateInfo.arraySize = 1; + swapchainCreateInfo.format = mSwapchainColorFormat; + swapchainCreateInfo.width = mWidth; + swapchainCreateInfo.height = mHeight; + swapchainCreateInfo.mipCount = 1; + swapchainCreateInfo.faceCount = 1; + swapchainCreateInfo.sampleCount = 1; + swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; + //CHECK_XRCMD(xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain)); + auto res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain); + if (XR_SUCCEEDED(res)) + break; + else + { + Log(Debug::Verbose) << "Failed to create swapchain with SampleCount=" << mSamples << ": " << XrResultString(res); + mSamples /= 2; + if(mSamples == 0) + std::runtime_error(XrResultString(res)); + } + } + + uint32_t imageCount = 0; + CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr)); + + mSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR }); + CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast(mSwapchainImageBuffers.data()))); + //for (const auto& swapchainImage : mSwapchainImageBuffers) + // mTextureBuffers.push_back(new VRTexture(state, swapchainImage.image, mWidth, mHeight, 0)); + for (unsigned i = 0; i < imageCount; i++) + mRenderBuffers.emplace_back(new VRTexture(state, mWidth, mHeight, mSamples)); + + mSubImage.swapchain = mSwapchain; + mSubImage.imageRect.offset = { 0, 0 }; + mSubImage.imageRect.extent = { mWidth, mHeight }; + } + + OpenXRSwapchainImpl::~OpenXRSwapchainImpl() + { + if (mSwapchain) + CHECK_XRCMD(xrDestroySwapchain(mSwapchain)); + } + + VRTexture* OpenXRSwapchainImpl::renderBuffer() const + { + return mRenderBuffers[mRenderBuffer].get(); + } + + uint32_t OpenXRSwapchainImpl::acquiredImage() const + { + if(isAcquired()) + return mSwapchainImageBuffers[mAcquiredImageIndex].image; + throw std::logic_error("Swapbuffer not acquired before use"); + } + + bool OpenXRSwapchainImpl::isAcquired() const + { + return mIsAcquired; + } + + void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc) + { + mRenderBuffer = (mRenderBuffer + 1) % mRenderBuffers.size(); + renderBuffer()->beginFrame(gc); + } + + int swapCount = 0; + + void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc) + { + // Blit frame to swapchain + acquire(gc); + renderBuffer()->endFrame(gc, acquiredImage()); + release(gc); + } + + void OpenXRSwapchainImpl::acquire(osg::GraphicsContext* gc) + { + XrSwapchainImageAcquireInfo acquireInfo{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO }; + CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchain, &acquireInfo, &mAcquiredImageIndex)); + + XrSwapchainImageWaitInfo waitInfo{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; + waitInfo.timeout = XR_INFINITE_DURATION; + CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo)); + + mIsAcquired = true; + } + + void OpenXRSwapchainImpl::release(osg::GraphicsContext* gc) + { + mIsAcquired = false; + + XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO }; + CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo)); + } +} diff --git a/apps/openmw/mwvr/openxrswapchainimpl.hpp b/apps/openmw/mwvr/openxrswapchainimpl.hpp new file mode 100644 index 000000000..2f850cb59 --- /dev/null +++ b/apps/openmw/mwvr/openxrswapchainimpl.hpp @@ -0,0 +1,50 @@ +#ifndef OPENXR_SWAPCHAINIMPL_HPP +#define OPENXR_SWAPCHAINIMPL_HPP + +#include "openxrswapchain.hpp" +#include "openxrmanagerimpl.hpp" + +struct XrSwapchainSubImage; + +namespace MWVR +{ + +class OpenXRSwapchainImpl +{ +public: + OpenXRSwapchainImpl(osg::ref_ptr state, SwapchainConfig config); + ~OpenXRSwapchainImpl(); + + void beginFrame(osg::GraphicsContext* gc); + void endFrame(osg::GraphicsContext* gc); + void acquire(osg::GraphicsContext* gc); + void release(osg::GraphicsContext* gc); + + VRTexture* renderBuffer() const; + + uint32_t acquiredImage() const; + + bool isAcquired() const; + XrSwapchain xrSwapchain(void) const { return mSwapchain; }; + XrSwapchainSubImage xrSubImage(void) const { return mSubImage; }; + int width() const { return mWidth; }; + int height() const { return mHeight; }; + int samples() const { return mSamples; }; + + XrSwapchain mSwapchain = XR_NULL_HANDLE; + std::vector mSwapchainImageBuffers{}; + //std::vector > mTextureBuffers{}; + XrSwapchainSubImage mSubImage{}; + int32_t mWidth = -1; + int32_t mHeight = -1; + int32_t mSamples = -1; + int64_t mSwapchainColorFormat = -1; + uint32_t mFBO = 0; + std::vector > mRenderBuffers{}; + int mRenderBuffer{ 0 }; + uint32_t mAcquiredImageIndex{ 0 }; + bool mIsAcquired{ false }; +}; +} + +#endif diff --git a/apps/openmw/mwvr/vrviewer.cpp b/apps/openmw/mwvr/vrviewer.cpp index 57d1cd323..940c22cb1 100644 --- a/apps/openmw/mwvr/vrviewer.cpp +++ b/apps/openmw/mwvr/vrviewer.cpp @@ -112,6 +112,14 @@ namespace MWVR mViewer->setReleaseContextAtEndOfFrameHint(false); mMirrorTexture.reset(new VRTexture(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0)); + mMsaaResolveMirrorTexture[(int)Side::LEFT_SIDE].reset(new VRTexture(context->getState(), + leftView->swapchain().width(), + leftView->swapchain().height(), + 0)); + mMsaaResolveMirrorTexture[(int)Side::RIGHT_SIDE].reset(new VRTexture(context->getState(), + rightView->swapchain().width(), + rightView->swapchain().height(), + 0)); mViewer->getSlave(0)._updateSlaveCallback = new VRView::UpdateSlaveCallback(leftView, context); mViewer->getSlave(1)._updateSlaveCallback = new VRView::UpdateSlaveCallback(rightView, context); @@ -138,15 +146,26 @@ namespace MWVR { auto* state = gc->getState(); auto* gl = osg::GLExtensions::Get(state->getContextID(), false); - int mirror_width = mMirrorTexture->width() / 2; - mMirrorTexture->beginFrame(gc); - mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTexture->height()); - mViews["LeftEye"]->swapchain().renderBuffer()->blit(gc, mirror_width, 0, 2 * mirror_width, mMirrorTexture->height()); + int screenWidth = mCameras["MainCamera"]->getViewport()->width(); + int mirrorWidth = screenWidth / 2; + int screenHeight = mCameras["MainCamera"]->getViewport()->height(); + const char* viewNames[] = { + "RightEye", + "LeftEye" + }; + + for (int i = 0; i < 2; i++) + { + auto& resolveTexture = *mMsaaResolveMirrorTexture[i]; + resolveTexture.beginFrame(gc); + mViews[viewNames[i]]->swapchain().renderBuffer()->blit(gc, 0, 0, resolveTexture.width(), resolveTexture.height()); + mMirrorTexture->beginFrame(gc); + resolveTexture.blit(gc, i * mirrorWidth, 0, (i + 1) * mirrorWidth, screenHeight); + } gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - mMirrorTexture->blit(gc, 0, 0, mMirrorTexture->width(), mMirrorTexture->height()); - + mMirrorTexture->blit(gc, 0, 0, screenWidth, screenHeight); } void diff --git a/apps/openmw/mwvr/vrviewer.hpp b/apps/openmw/mwvr/vrviewer.hpp index fa52f499a..c35c732ef 100644 --- a/apps/openmw/mwvr/vrviewer.hpp +++ b/apps/openmw/mwvr/vrviewer.hpp @@ -91,6 +91,8 @@ namespace MWVR osg::ref_ptr mPreDraw{ nullptr }; osg::ref_ptr mPostDraw{ nullptr }; osg::GraphicsContext* mMainCameraGC{ nullptr }; + //std::unique_ptr mMirrorTexture{ nullptr }; + std::unique_ptr mMsaaResolveMirrorTexture[2]{ }; std::unique_ptr mMirrorTexture{ nullptr }; std::mutex mMutex;