From 7e9690e53160b226e1b238cf50a3a81d15e848ea Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Mon, 30 Oct 2023 10:57:13 -0700 Subject: [PATCH] [renderer] render scene exclusively to fbo --- apps/openmw/mwrender/npcanimation.cpp | 51 ++-- apps/openmw/mwrender/pingpongcanvas.cpp | 67 ++--- apps/openmw/mwrender/pingpongcanvas.hpp | 72 ++--- apps/openmw/mwrender/pingpongcull.cpp | 30 +- apps/openmw/mwrender/postprocessor.cpp | 308 ++++++++------------- apps/openmw/mwrender/postprocessor.hpp | 66 ++--- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/screenshotmanager.cpp | 21 +- 8 files changed, 222 insertions(+), 395 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cb7ef3626f9..669a6fae45f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -328,46 +328,37 @@ namespace MWRender { osg::State* state = renderInfo.getState(); - PostProcessor* postProcessor = dynamic_cast(renderInfo.getCurrentCamera()->getUserData()); + PostProcessor* postProcessor = static_cast(renderInfo.getCurrentCamera()->getUserData()); state->applyAttribute(mDepth); unsigned int frameId = state->getFrameStamp()->getFrameNumber() % 2; - if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)) + postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)->apply(*state); + if (mPassNormals) { - postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)->apply(*state); - if (mPassNormals) - { - state->get()->glColorMaski(1, true, true, true, true); - state->haveAppliedAttribute(osg::StateAttribute::COLORMASK); - } - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // color accumulation pass - bin->drawImplementation(renderInfo, previous); + state->get()->glColorMaski(1, true, true, true, true); + state->haveAppliedAttribute(osg::StateAttribute::COLORMASK); + } + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + // color accumulation pass + bin->drawImplementation(renderInfo, previous); - auto primaryFBO = postProcessor->getPrimaryFbo(frameId); + auto primaryFBO = postProcessor->getPrimaryFbo(frameId); - if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)) - postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state); - else - primaryFBO->apply(*state); + if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)) + postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state); + else + primaryFBO->apply(*state); - // depth accumulation pass - osg::ref_ptr restore = bin->getStateSet(); - bin->setStateSet(mStateSet); - bin->drawImplementation(renderInfo, previous); - bin->setStateSet(restore); + // depth accumulation pass + osg::ref_ptr restore = bin->getStateSet(); + bin->setStateSet(mStateSet); + bin->drawImplementation(renderInfo, previous); + bin->setStateSet(restore); - if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)) - primaryFBO->apply(*state); - } - else - { - // fallback to standard depth clear when we are not rendering our main scene via an intermediate FBO - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - bin->drawImplementation(renderInfo, previous); - } + if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)) + primaryFBO->apply(*state); state->checkGLErrors("after DepthClearCallback::drawImplementation"); } diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index 6a56f7e5f76..5ac68acf5fc 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -43,19 +43,16 @@ namespace MWRender mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0)); } - void PingPongCanvas::setCurrentFrameData(size_t frameId, fx::DispatchArray&& data) + void PingPongCanvas::setPasses(fx::DispatchArray&& passes) { - mBufferData[frameId].data = std::move(data); + mPasses = std::move(passes); } - void PingPongCanvas::setMask(size_t frameId, bool underwater, bool exterior) + void PingPongCanvas::setMask(bool underwater, bool exterior) { - mBufferData[frameId].mask = 0; - - mBufferData[frameId].mask - |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater; - mBufferData[frameId].mask - |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors; + mMask = 0; + mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater; + mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors; } void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const @@ -77,19 +74,15 @@ namespace MWRender size_t frameId = state.getFrameStamp()->getFrameNumber() % 2; - auto& bufferData = mBufferData[frameId]; - - const auto& data = bufferData.data; - std::vector filtered; - filtered.reserve(data.size()); + filtered.reserve(mPasses.size()); - for (size_t i = 0; i < data.size(); ++i) + for (size_t i = 0; i < mPasses.size(); ++i) { - const auto& node = data[i]; + const auto& node = mPasses[i]; - if (bufferData.mask & node.mFlags) + if (mMask & node.mFlags) continue; filtered.push_back(i); @@ -97,7 +90,7 @@ namespace MWRender auto* resolveViewport = state.getCurrentViewport(); - if (filtered.empty() || !bufferData.postprocessing) + if (filtered.empty() || !mPostprocessing) { state.pushStateSet(mFallbackStateSet); state.apply(); @@ -108,7 +101,7 @@ namespace MWRender state.apply(); } - state.applyTextureAttribute(0, bufferData.sceneTex); + state.applyTextureAttribute(0, mTextureScene); resolveViewport->apply(state); drawGeometry(renderInfo); @@ -124,13 +117,12 @@ namespace MWRender const unsigned int handle = mFbos[0] ? mFbos[0]->getHandle(state.getContextID()) : 0; - if (handle == 0 || bufferData.dirty) + if (handle == 0 || mDirty) { for (auto& fbo : mFbos) { fbo = new osg::FrameBufferObject; - attachCloneOfTemplate( - fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR); + attachCloneOfTemplate(fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene); fbo->apply(state); glClearColor(0.5, 0.5, 0.5, 1); glClear(GL_COLOR_BUFFER_BIT); @@ -140,7 +132,7 @@ namespace MWRender { mMultiviewResolveFramebuffer = new osg::FrameBufferObject(); attachCloneOfTemplate(mMultiviewResolveFramebuffer, - osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR); + osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene); mMultiviewResolveFramebuffer->apply(state); glClearColor(0.5, 0.5, 0.5, 1); glClear(GL_COLOR_BUFFER_BIT); @@ -150,15 +142,15 @@ namespace MWRender .getTexture()); } - mLuminanceCalculator.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight()); + mLuminanceCalculator.dirty(mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight()); if (Stereo::getStereo()) - mRenderViewport = new osg::Viewport( - 0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight()); + mRenderViewport + = new osg::Viewport(0, 0, mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight()); else mRenderViewport = nullptr; - bufferData.dirty = false; + mDirty = false; } constexpr std::array, 3> buffers @@ -166,7 +158,7 @@ namespace MWRender { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT2_EXT }, { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT } } }; - (bufferData.hdr) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable(); + (mAvgLum) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable(); // A histogram based approach is superior way to calculate scene luminance. Using mipmaps is more broadly // supported, so that's what we use for now. @@ -181,8 +173,7 @@ namespace MWRender const unsigned int cid = state.getContextID(); - const osg::ref_ptr& destinationFbo - = bufferData.destination ? bufferData.destination : nullptr; + const osg::ref_ptr& destinationFbo = mDestinationFBO ? mDestinationFBO : nullptr; unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0; auto bindDestinationFbo = [&]() { @@ -206,17 +197,16 @@ namespace MWRender for (const size_t& index : filtered) { - const auto& node = data[index]; + const auto& node = mPasses[index]; - node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, bufferData.depthTex); + node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, mTextureDepth); - if (bufferData.hdr) + if (mAvgLum) node.mRootStateSet->setTextureAttribute( PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId)); - if (bufferData.normalsTex) - node.mRootStateSet->setTextureAttribute( - PostProcessor::TextureUnits::Unit_Normals, bufferData.normalsTex); + if (mTextureNormals) + node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals); state.pushStateSet(node.mRootStateSet); state.apply(); @@ -231,7 +221,7 @@ namespace MWRender // VR-TODO: This won't actually work for tex2darrays if (lastShader == 0) - pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, bufferData.sceneTex); + pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, mTextureScene); else pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, (osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT] @@ -239,7 +229,7 @@ namespace MWRender .getTexture()); if (lastDraw == 0) - pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, bufferData.sceneTex); + pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, mTextureScene); else pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, (osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT] @@ -260,7 +250,6 @@ namespace MWRender } lastApplied = pass.mRenderTarget->getHandle(state.getContextID()); - ; } else if (pass.mResolve && index == filtered.back()) { diff --git a/apps/openmw/mwrender/pingpongcanvas.hpp b/apps/openmw/mwrender/pingpongcanvas.hpp index a5557a6d6e7..d8758303d7a 100644 --- a/apps/openmw/mwrender/pingpongcanvas.hpp +++ b/apps/openmw/mwrender/pingpongcanvas.hpp @@ -24,76 +24,52 @@ namespace MWRender public: PingPongCanvas(Shader::ShaderManager& shaderManager); - void drawImplementation(osg::RenderInfo& renderInfo) const override; + void drawGeometry(osg::RenderInfo& renderInfo) const; - void dirty(size_t frameId) { mBufferData[frameId].dirty = true; } + void drawImplementation(osg::RenderInfo& renderInfo) const override; - const fx::DispatchArray& getCurrentFrameData(size_t frame) { return mBufferData[frame % 2].data; } + void dirty() { mDirty = true; } - // Sets current frame pass data and stores copy of dispatch array to apply to next frame data - void setCurrentFrameData(size_t frameId, fx::DispatchArray&& data); + const fx::DispatchArray& getPasses() { return mPasses; } - void setMask(size_t frameId, bool underwater, bool exterior); + void setPasses(fx::DispatchArray&& passes); - void setSceneTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].sceneTex = tex; } + void setMask(bool underwater, bool exterior); - void setLDRSceneTexture(size_t frameId, osg::ref_ptr tex) - { - mBufferData[frameId].sceneTexLDR = tex; - } + void setTextureScene(osg::ref_ptr tex) { mTextureScene = tex; } - void setDepthTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].depthTex = tex; } + void setTextureDepth(osg::ref_ptr tex) { mTextureDepth = tex; } - void setNormalsTexture(size_t frameId, osg::ref_ptr tex) - { - mBufferData[frameId].normalsTex = tex; - } + void setTextureNormals(osg::ref_ptr tex) { mTextureNormals = tex; } - void setHDR(size_t frameId, bool hdr) { mBufferData[frameId].hdr = hdr; } + void setCalculateAvgLum(bool enabled) { mAvgLum = enabled; } - void setPostProcessing(size_t frameId, bool postprocessing) - { - mBufferData[frameId].postprocessing = postprocessing; - } + void setPostProcessing(bool enabled) { mPostprocessing = enabled; } - const osg::ref_ptr& getSceneTexture(size_t frameId) const - { - return mBufferData[frameId].sceneTex; - } - - void drawGeometry(osg::RenderInfo& renderInfo) const; + const osg::ref_ptr& getSceneTexture(size_t frameId) const { return mTextureScene; } private: - void copyNewFrameData(size_t frameId) const; + bool mAvgLum = false; + bool mPostprocessing = false; - mutable LuminanceCalculator mLuminanceCalculator; + fx::DispatchArray mPasses; + fx::FlagsType mMask; osg::ref_ptr mFallbackProgram; osg::ref_ptr mMultiviewResolveProgram; osg::ref_ptr mFallbackStateSet; osg::ref_ptr mMultiviewResolveStateSet; - mutable osg::ref_ptr mMultiviewResolveFramebuffer; - struct BufferData - { - bool dirty = false; - bool hdr = false; - bool postprocessing = true; + osg::ref_ptr mTextureScene; + osg::ref_ptr mTextureDepth; + osg::ref_ptr mTextureNormals; - fx::DispatchArray data; - fx::FlagsType mask; - - osg::ref_ptr destination; - - osg::ref_ptr sceneTex; - osg::ref_ptr depthTex; - osg::ref_ptr sceneTexLDR; - osg::ref_ptr normalsTex; - }; - - mutable std::array mBufferData; - mutable std::array, 3> mFbos; + mutable bool mDirty = false; mutable osg::ref_ptr mRenderViewport; + mutable osg::ref_ptr mMultiviewResolveFramebuffer; + mutable osg::ref_ptr mDestinationFBO; + mutable std::array, 3> mFbos; + mutable LuminanceCalculator mLuminanceCalculator; }; } diff --git a/apps/openmw/mwrender/pingpongcull.cpp b/apps/openmw/mwrender/pingpongcull.cpp index 8dfff5a60c8..497c6c734ac 100644 --- a/apps/openmw/mwrender/pingpongcull.cpp +++ b/apps/openmw/mwrender/pingpongcull.cpp @@ -21,7 +21,7 @@ namespace MWRender if (Stereo::getStereo()) { mViewportStateset = new osg::StateSet(); - mViewport = new osg::Viewport(0, 0, pp->renderWidth(), pp->renderHeight()); + mViewport = new osg::Viewport; mViewportStateset->setAttribute(mViewport); } } @@ -37,41 +37,31 @@ namespace MWRender size_t frame = cv->getTraversalNumber(); size_t frameId = frame % 2; - MWRender::PostProcessor* postProcessor - = dynamic_cast(cv->getCurrentCamera()->getUserData()); - if (!postProcessor) - throw std::runtime_error("PingPongCull: failed to get a PostProcessor!"); - if (Stereo::getStereo()) { auto& sm = Stereo::Manager::instance(); auto view = sm.getEye(cv); int index = view == Stereo::Eye::Right ? 1 : 0; auto projectionMatrix = sm.computeEyeProjection(index, true); - postProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix); + mPostProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix); } - postProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix()); - postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]); + mPostProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix()); + mPostProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]); mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix(); - postProcessor->getStateUpdater()->setEyePos(cv->getEyePoint()); - postProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal()); + mPostProcessor->getStateUpdater()->setEyePos(cv->getEyePoint()); + mPostProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal()); - if (!postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)) - { - renderStage->setMultisampleResolveFramebufferObject(nullptr); - renderStage->setFrameBufferObject(nullptr); - } - else if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)) + if (!mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)) { - renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); + renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); } else { renderStage->setMultisampleResolveFramebufferObject( - postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); - renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)); + mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); + renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)); // The MultiView patch has a bug where it does not update resolve layers if the resolve framebuffer is // changed. So we do blit manually in this case diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index a6945de2996..c3106802db5 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -110,30 +110,45 @@ namespace MWRender PostProcessor::PostProcessor( RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs) : osg::Group() - , mEnableLiveReload(false) , mRootNode(rootNode) - , mSamples(Settings::video().mAntialiasing) - , mDirty(false) - , mDirtyFrameId(0) + , mHUDCamera(new osg::Camera) , mRendering(rendering) , mViewer(viewer) , mVFS(vfs) - , mTriggerShaderReload(false) - , mReload(false) - , mEnabled(false) , mUsePostProcessing(Settings::postProcessing().mEnabled) - , mDisableDepthPasses(false) - , mLastFrameNumber(0) - , mLastSimulationTime(0.f) - , mExteriorFlag(false) - , mUnderwater(false) - , mHDR(false) - , mNormals(false) - , mPrevNormals(false) - , mNormalsSupported(false) - , mPassLights(false) - , mPrevPassLights(false) + , mSamples(Settings::video().mAntialiasing) + , mPingPongCull(new PingPongCull(this)) + , mCanvases({ new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()), + new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()) }) { + mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER); + mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0)); + mHUDCamera->setClearMask(0); + mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1)); + mHUDCamera->setAllowEventFocus(false); + mHUDCamera->setViewport(0, 0, mWidth, mHeight); + mHUDCamera->setNodeMask(Mask_RenderToTexture); + mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mHUDCamera->addChild(mCanvases[0]); + mHUDCamera->addChild(mCanvases[1]); + mHUDCamera->setCullCallback(new HUDCullCallback); + mViewer->getCamera()->addCullCallback(mPingPongCull); + + if (Settings::shaders().mSoftParticles || Settings::postProcessing().mTransparentPostpass) + { + mTransparentDepthPostPass + = new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(), + Settings::postProcessing().mTransparentPostpass); + osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass); + } + + createObjectsForFrame(0); + createObjectsForFrame(1); + + populateTechniqueFiles(); + osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); osg::GLExtensions* ext = gc->getState()->get(); @@ -169,11 +184,18 @@ namespace MWRender mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; mStateUpdater = new fx::StateUpdater(mUBO); - if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles - && !mUsePostProcessing) - return; + addChild(mHUDCamera); + addChild(mRootNode); - enable(mUsePostProcessing); + mViewer->setSceneData(this); + mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this)); + mViewer->getCamera()->setUserData(this); + + setCullCallback(mStateUpdater); + + if (mUsePostProcessing) + enable(); } PostProcessor::~PostProcessor() @@ -202,7 +224,6 @@ namespace MWRender size_t frameId = frame() % 2; - createTexturesAndCamera(frameId); createObjectsForFrame(frameId); mRendering.updateProjectionMatrix(); @@ -210,8 +231,6 @@ namespace MWRender dirtyTechniques(); - mPingPongCanvas->dirty(frameId); - mDirty = true; mDirtyFrameId = !frameId; } @@ -230,77 +249,20 @@ namespace MWRender } } - void PostProcessor::enable(bool usePostProcessing) + void PostProcessor::enable() { mReload = true; - mEnabled = true; - const bool postPass = Settings::postProcessing().mTransparentPostpass; - mUsePostProcessing = usePostProcessing; - - mDisableDepthPasses = !Settings::shaders().mSoftParticles && !postPass; - -#ifdef ANDROID - mDisableDepthPasses = true; -#endif - - if (!mDisableDepthPasses) - { - mTransparentDepthPostPass = new TransparentDepthBinCallback( - mRendering.getResourceSystem()->getSceneManager()->getShaderManager(), postPass); - osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass); - } - - if (mUsePostProcessing && mTechniqueFileMap.empty()) - { - populateTechniqueFiles(); - } - - createTexturesAndCamera(frame() % 2); - - removeChild(mHUDCamera); - removeChild(mRootNode); - - addChild(mHUDCamera); - addChild(mRootNode); - - mViewer->setSceneData(this); - mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); - mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this)); - mViewer->getCamera()->setUserData(this); - - setCullCallback(mStateUpdater); - mHUDCamera->setCullCallback(new HUDCullCallback); + mUsePostProcessing = true; } void PostProcessor::disable() { - if (!Settings::shaders().mSoftParticles) - osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr); - - if (!SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles) - { - removeChild(mHUDCamera); - setCullCallback(nullptr); - - mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER); - mViewer->getCamera()->getGraphicsContext()->setResizedCallback(nullptr); - mViewer->getCamera()->setUserData(nullptr); - - mEnabled = false; - } - mUsePostProcessing = false; mRendering.getSkyManager()->setSunglare(true); } void PostProcessor::traverse(osg::NodeVisitor& nv) { - if (!mEnabled) - { - osg::Group::traverse(nv); - return; - } - size_t frameId = nv.getTraversalNumber() % 2; if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) @@ -313,26 +275,23 @@ namespace MWRender void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv) { - const auto& fbo = getFbo(FBO_Intercept, frameId); - if (fbo) + if (const auto& fbo = getFbo(FBO_Intercept, frameId)) { osgUtil::RenderStage* rs = cv->getRenderStage(); if (rs && rs->getMultisampleResolveFramebufferObject()) rs->setMultisampleResolveFramebufferObject(fbo); } - mPingPongCanvas->setPostProcessing(frameId, mUsePostProcessing); - mPingPongCanvas->setNormalsTexture(frameId, mNormals ? getTexture(Tex_Normal, frameId) : nullptr); - mPingPongCanvas->setMask(frameId, mUnderwater, mExteriorFlag); - mPingPongCanvas->setHDR(frameId, getHDR()); + mCanvases[frameId]->setPostProcessing(mUsePostProcessing); + mCanvases[frameId]->setTextureNormals(mNormals ? getTexture(Tex_Normal, frameId) : nullptr); + mCanvases[frameId]->setMask(mUnderwater, mExteriorFlag); + mCanvases[frameId]->setCalculateAvgLum(mHDR); - mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId)); - if (mDisableDepthPasses) - mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_Depth, frameId)); + mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId)); + if (mTransparentDepthPostPass) + mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId)); else - mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_OpaqueDepth, frameId)); - - mPingPongCanvas->setLDRSceneTexture(frameId, getTexture(Tex_Scene_LDR, frameId)); + mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId)); if (mTransparentDepthPostPass) { @@ -355,7 +314,7 @@ namespace MWRender mStateUpdater->setDeltaSimulationTime(static_cast(stamp->getSimulationTime() - mLastSimulationTime)); mLastSimulationTime = stamp->getSimulationTime(); - for (const auto& dispatchNode : mPingPongCanvas->getCurrentFrameData(frame)) + for (const auto& dispatchNode : mCanvases[frameId]->getPasses()) { for (auto& uniform : dispatchNode.mHandle->getUniformMap()) { @@ -421,13 +380,15 @@ namespace MWRender reloadIfRequired(); + mCanvases[frameId]->setNodeMask(~0u); + mCanvases[!frameId]->setNodeMask(0); + if (mDirty && mDirtyFrameId == frameId) { - createTexturesAndCamera(frameId); createObjectsForFrame(frameId); - mDirty = false; - mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData)); + mDirty = false; + mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData)); } if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights)) @@ -448,7 +409,6 @@ namespace MWRender mViewer->startThreading(); - createTexturesAndCamera(frameId); createObjectsForFrame(frameId); mDirty = true; @@ -458,19 +418,55 @@ namespace MWRender void PostProcessor::createObjectsForFrame(size_t frameId) { - auto& fbos = mFbos[frameId]; auto& textures = mTextures[frameId]; - auto width = renderWidth(); - auto height = renderHeight(); - for (auto& tex : textures) + int width = renderWidth(); + int height = renderHeight(); + + for (osg::ref_ptr& texture : textures) { - if (!tex) - continue; + if (!texture) + { + if (Stereo::getMultiview()) + texture = new osg::Texture2DArray; + else + texture = new osg::Texture2D; + } + Stereo::setMultiviewCompatibleTextureSize(texture, width, height); + texture->setSourceFormat(GL_RGBA); + texture->setSourceType(GL_UNSIGNED_BYTE); + texture->setInternalFormat(GL_RGBA); + texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setResizeNonPowerOfTwoHint(false); + Stereo::setMultiviewCompatibleTextureSize(texture, width, height); + texture->dirtyTextureObject(); + } - Stereo::setMultiviewCompatibleTextureSize(tex, width, height); - tex->dirtyTextureObject(); + textures[Tex_Normal]->setSourceFormat(GL_RGB); + textures[Tex_Normal]->setInternalFormat(GL_RGB); + + auto setupDepth = [](osg::Texture* tex) { + tex->setSourceFormat(GL_DEPTH_STENCIL_EXT); + tex->setSourceType(SceneUtil::AutoDepth::depthSourceType()); + tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()); + }; + + setupDepth(textures[Tex_Depth]); + + if (!mTransparentDepthPostPass) + { + textures[Tex_OpaqueDepth] = nullptr; } + else + { + setupDepth(textures[Tex_OpaqueDepth]); + textures[Tex_OpaqueDepth]->setName("opaqueTexMap"); + } + + auto& fbos = mFbos[frameId]; fbos[FBO_Primary] = new osg::FrameBufferObject; fbos[FBO_Primary]->setAttachment( @@ -534,13 +530,12 @@ namespace MWRender osg::FrameBufferAttachment(new osg::RenderBuffer(textures[Tex_OpaqueDepth]->getTextureWidth(), textures[Tex_OpaqueDepth]->getTextureHeight(), textures[Tex_Scene]->getInternalFormat()))); #endif + + mCanvases[frameId]->dirty(); } void PostProcessor::dirtyTechniques() { - if (!isEnabled()) - return; - size_t frameId = frame() % 2; mDirty = true; @@ -667,7 +662,7 @@ namespace MWRender mTemplateData.emplace_back(std::move(node)); } - mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData)); + mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData)); if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud()) hud->updateTechniques(); @@ -678,12 +673,6 @@ namespace MWRender PostProcessor::Status PostProcessor::enableTechnique( std::shared_ptr technique, std::optional location) { - if (!isEnabled()) - { - Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'"; - return Status_Error; - } - if (!technique || technique->getLocked() || (location.has_value() && location.value() < 0)) return Status_Error; @@ -721,86 +710,8 @@ namespace MWRender return technique->isValid(); } - void PostProcessor::createTexturesAndCamera(size_t frameId) - { - auto& textures = mTextures[frameId]; - - auto width = renderWidth(); - auto height = renderHeight(); - - for (auto& texture : textures) - { - if (!texture) - { - if (Stereo::getMultiview()) - texture = new osg::Texture2DArray; - else - texture = new osg::Texture2D; - } - Stereo::setMultiviewCompatibleTextureSize(texture, width, height); - texture->setSourceFormat(GL_RGBA); - texture->setSourceType(GL_UNSIGNED_BYTE); - texture->setInternalFormat(GL_RGBA); - texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR); - texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - texture->setResizeNonPowerOfTwoHint(false); - } - - textures[Tex_Normal]->setSourceFormat(GL_RGB); - textures[Tex_Normal]->setInternalFormat(GL_RGB); - - auto setupDepth = [](osg::Texture* tex) { - tex->setSourceFormat(GL_DEPTH_STENCIL_EXT); - tex->setSourceType(SceneUtil::AutoDepth::depthSourceType()); - tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()); - }; - - setupDepth(textures[Tex_Depth]); - - if (mDisableDepthPasses) - { - textures[Tex_OpaqueDepth] = nullptr; - } - else - { - setupDepth(textures[Tex_OpaqueDepth]); - textures[Tex_OpaqueDepth]->setName("opaqueTexMap"); - } - - if (mHUDCamera) - return; - - mHUDCamera = new osg::Camera; - mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); - mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER); - mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0)); - mHUDCamera->setClearMask(0); - mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1)); - mHUDCamera->setAllowEventFocus(false); - mHUDCamera->setViewport(0, 0, mWidth, mHeight); - - mViewer->getCamera()->removeCullCallback(mPingPongCull); - mPingPongCull = new PingPongCull(this); - mViewer->getCamera()->addCullCallback(mPingPongCull); - - mPingPongCanvas = new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()); - mHUDCamera->addChild(mPingPongCanvas); - mHUDCamera->setNodeMask(Mask_RenderToTexture); - - mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - } - std::shared_ptr PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame) { - if (!isEnabled()) - { - Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << name << "'"; - return nullptr; - } - for (const auto& technique : mTemplates) if (Misc::StringUtils::ciEqual(technique->getName(), name)) return technique; @@ -831,9 +742,6 @@ namespace MWRender void PostProcessor::loadChain() { - if (!isEnabled()) - return; - mTechniques.clear(); for (const std::string& techniqueName : Settings::postProcessing().mChain.get()) diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index 4473ade8368..153ec8166b2 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -115,14 +115,14 @@ namespace MWRender return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary]; } + osg::ref_ptr getHUDCamera() { return mHUDCamera; } + osg::ref_ptr getStateUpdater() { return mStateUpdater; } const TechniqueList& getTechniques() { return mTechniques; } const TechniqueList& getTemplates() const { return mTemplates; } - osg::ref_ptr getCanvas() { return mPingPongCanvas; } - const auto& getTechniqueMap() const { return mTechniqueFileMap; } void resize(); @@ -173,13 +173,11 @@ namespace MWRender std::shared_ptr loadTechnique(const std::string& name, bool loadNextFrame = false); - bool isEnabled() const { return mUsePostProcessing && mEnabled; } - - bool getHDR() const { return mHDR; } + bool isEnabled() const { return mUsePostProcessing; } void disable(); - void enable(bool usePostProcessing = true); + void enable(); void setRenderTargetSize(int width, int height) { @@ -194,7 +192,7 @@ namespace MWRender void triggerShaderReload(); - bool mEnableLiveReload; + bool mEnableLiveReload = false; void loadChain(); void saveChain(); @@ -206,10 +204,6 @@ namespace MWRender void createObjectsForFrame(size_t frameId); - void createTexturesAndCamera(size_t frameId); - - void reloadMainPass(fx::Technique& technique); - void dirtyTechniques(); void update(size_t frameId); @@ -232,43 +226,39 @@ namespace MWRender std::unordered_map mTechniqueFileMap; - int mSamples; - - bool mDirty; - size_t mDirtyFrameId; - RenderingManager& mRendering; osgViewer::Viewer* mViewer; const VFS::Manager* mVFS; - bool mTriggerShaderReload; - bool mReload; - bool mEnabled; - bool mUsePostProcessing; - bool mDisableDepthPasses; - - size_t mLastFrameNumber; - float mLastSimulationTime; - - bool mExteriorFlag; - bool mUnderwater; - bool mHDR; - bool mNormals; - bool mPrevNormals; - bool mNormalsSupported; - bool mPassLights; - bool mPrevPassLights; - bool mUBO; + size_t mDirtyFrameId = 0; + size_t mLastFrameNumber = 0; + float mLastSimulationTime = 0.f; + + bool mDirty = false; + bool mReload = true; + bool mTriggerShaderReload = false; + bool mUsePostProcessing = false; + + bool mUBO = false; + bool mHDR = false; + bool mNormals = false; + bool mUnderwater = false; + bool mPassLights = false; + bool mPrevNormals = false; + bool mExteriorFlag = false; + bool mNormalsSupported = false; + bool mPrevPassLights = false; + int mGLSLVersion; + int mWidth; + int mHeight; + int mSamples; osg::ref_ptr mStateUpdater; osg::ref_ptr mPingPongCull; - osg::ref_ptr mPingPongCanvas; + std::array, 2> mCanvases; osg::ref_ptr mTransparentDepthPostPass; - int mWidth; - int mHeight; - fx::DispatchArray mTemplateData; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 090e6be3120..3b6716ce2c2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1256,7 +1256,7 @@ namespace MWRender mSharedUniformStateUpdater->setScreenRes(res.x(), res.y()); Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix()); } - else if (!mPostProcessor->isEnabled()) + else { mSharedUniformStateUpdater->setScreenRes(width, height); } diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index b4bdda0a282..a23d242a155 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -21,6 +21,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "postprocessor.hpp" #include "util.hpp" @@ -102,24 +103,6 @@ namespace MWRender int width = screenW - leftPadding * 2; int height = screenH - topPadding * 2; - // Ensure we are reading from the resolved framebuffer and not the multisampled render buffer. Also ensure - // that the readbuffer is set correctly with rendeirng to FBO. glReadPixel() cannot read from multisampled - // targets - PostProcessor* postProcessor = dynamic_cast(renderInfo.getCurrentCamera()->getUserData()); - osg::GLExtensions* ext = osg::GLExtensions::Get(renderInfo.getContextID(), false); - - if (ext) - { - size_t frameId = renderInfo.getState()->getFrameStamp()->getFrameNumber() % 2; - osg::FrameBufferObject* fbo = nullptr; - - if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)) - fbo = postProcessor->getFbo(PostProcessor::FBO_Primary, frameId); - - if (fbo) - fbo->apply(*renderInfo.getState(), osg::FrameBufferObject::READ_FRAMEBUFFER); - } - mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE); mImage->scaleImage(mWidth, mHeight, 1); } @@ -145,7 +128,7 @@ namespace MWRender void ScreenshotManager::screenshot(osg::Image* image, int w, int h) { - osg::Camera* camera = mViewer->getCamera(); + osg::Camera* camera = MWBase::Environment::get().getWorld()->getPostProcessor()->getHUDCamera(); osg::ref_ptr tempDrw = new osg::Drawable; tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h)); tempDrw->setCullingActive(false);