From 3d030527175a1b128b5e1c2aba869e25d8ccef86 Mon Sep 17 00:00:00 2001 From: "glassmancody.info" Date: Wed, 18 May 2022 19:45:09 -0700 Subject: [PATCH] dont bind rendertargets unless we use them, otherwise texture limit will be reached quickly --- apps/openmw/mwlua/postprocessingbindings.cpp | 2 +- apps/openmw/mwrender/postprocessor.cpp | 18 ++++++++++++++---- components/fx/pass.cpp | 3 +++ components/fx/pass.hpp | 8 ++++++-- components/fx/technique.cpp | 15 +++++++++++++++ docs/source/reference/postprocessing/omwfx.rst | 18 +++++++++++++++++- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwlua/postprocessingbindings.cpp b/apps/openmw/mwlua/postprocessingbindings.cpp index b016c7716a..187c9c700b 100644 --- a/apps/openmw/mwlua/postprocessingbindings.cpp +++ b/apps/openmw/mwlua/postprocessingbindings.cpp @@ -79,7 +79,7 @@ namespace MWLua shader.mQueuedAction = true; context.mLuaManager->addAction( - [&] { MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos); }, + [=] { MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos); }, "Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil") ); }; diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index df42daa34c..7e347bdf6d 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -574,10 +574,11 @@ namespace MWRender uniform->setUniform(node.mRootStateSet->getOrCreateUniform(uniform->mName, type.value())); } - int subTexUnit = texUnit; + std::unordered_map renderTargetCache; for (const auto& pass : technique->getPasses()) { + int subTexUnit = texUnit; fx::DispatchNode::SubPass subPass; pass->prepareStateSet(subPass.mStateSet, technique->getName()); @@ -591,6 +592,7 @@ namespace MWRender const auto [w, h] = rt.mSize.get(mWidth, mHeight); subPass.mRenderTexture = new osg::Texture2D(*rt.mTarget); + renderTargetCache[rt.mTarget] = subPass.mRenderTexture; subPass.mRenderTexture->setTextureSize(w, h); subPass.mRenderTexture->setName(std::string(pass->getTarget())); @@ -600,10 +602,18 @@ namespace MWRender subPass.mRenderTarget = new osg::FrameBufferObject; subPass.mRenderTarget->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(subPass.mRenderTexture)); subPass.mStateSet->setAttributeAndModes(new osg::Viewport(0, 0, w, h)); - - node.mRootStateSet->setTextureAttributeAndModes(subTexUnit, subPass.mRenderTexture); - node.mRootStateSet->addUniform(new osg::Uniform(subPass.mRenderTexture->getName().c_str(), subTexUnit++)); } + + for (const auto& whitelist : pass->getRenderTargets()) + { + auto it = technique->getRenderTargetsMap().find(whitelist); + if (it != technique->getRenderTargetsMap().end() && renderTargetCache[it->second.mTarget]) + { + subPass.mStateSet->setTextureAttributeAndModes(subTexUnit, renderTargetCache[it->second.mTarget]); + subPass.mStateSet->addUniform(new osg::Uniform(std::string(it->first).c_str(), subTexUnit++)); + } + } + node.mPasses.emplace_back(std::move(subPass)); } diff --git a/components/fx/pass.cpp b/components/fx/pass.cpp index 246221eb84..5d9b9c4df7 100644 --- a/components/fx/pass.cpp +++ b/components/fx/pass.cpp @@ -200,6 +200,9 @@ float omw_GetPointLightRadius(int index) for (size_t pos = header.find(define); pos != std::string::npos; pos = header.find(define)) header.replace(pos, define.size(), value); + for (const auto& target : mRenderTargets) + header.append("uniform sampler2D " + std::string(target) + ";"); + for (auto& uniform : technique.getUniformMap()) if (auto glsl = uniform->getGLSL()) header.append(glsl.value()); diff --git a/components/fx/pass.hpp b/components/fx/pass.hpp index bd13c3f99b..1b8ea165e6 100644 --- a/components/fx/pass.hpp +++ b/components/fx/pass.hpp @@ -43,7 +43,9 @@ namespace fx void compile(Technique& technique, std::string_view preamble); - std::string_view getTarget() const { return mTarget; } + std::string getTarget() const { return mTarget; } + + const std::array& getRenderTargets() const { return mRenderTargets; } void prepareStateSet(osg::StateSet* stateSet, const std::string& name) const; @@ -67,7 +69,9 @@ namespace fx bool mUBO; bool mSupportsNormals; - std::string_view mTarget; + std::array mRenderTargets; + + std::string mTarget; std::optional mClearColor; std::optional mBlendSource; diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index c186f12c0c..94284d1ccd 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -822,6 +822,21 @@ namespace fx expect(); pass->mTarget = std::get(mToken).value; } + else if (key == "rt1") + { + expect(); + pass->mRenderTargets[0] = std::get(mToken).value; + } + else if (key == "rt2") + { + expect(); + pass->mRenderTargets[1] = std::get(mToken).value; + } + else if (key == "rt3") + { + expect(); + pass->mRenderTargets[2] =std::get(mToken).value; + } else if (key == "blend") { expect(); diff --git a/docs/source/reference/postprocessing/omwfx.rst b/docs/source/reference/postprocessing/omwfx.rst index eab70ba9d5..bf194c7929 100644 --- a/docs/source/reference/postprocessing/omwfx.rst +++ b/docs/source/reference/postprocessing/omwfx.rst @@ -500,7 +500,8 @@ is not wanted and you want a custom render target. To use the render target you must assign passes to it, along with any optional clear modes or custom blend modes. -In the code snippet below a rendertarget is used to draw the red cannel of a scene at half resolution. +In the code snippet below a rendertarget is used to draw the red cannel of a scene at half resolution, then a quarter. As a restriction, +only three render targets can be bound per pass with ``rt1``, ``rt2``, ``rt3``, respectively. .. code-block:: none @@ -512,6 +513,11 @@ In the code snippet below a rendertarget is used to draw the red cannel of a sce source_format = red; } + render_target RT_Downsample4 { + width_ratio = 0.25; + height_ratio = 0.25; + } + fragment downsample2x(target=RT_Downsample) { omw_In vec2 omw_TexCoord; @@ -522,6 +528,16 @@ In the code snippet below a rendertarget is used to draw the red cannel of a sce } } + fragment downsample4x(target=RT_Downsample4, rt1=RT_Downsample) { + + omw_In vec2 omw_TexCoord; + + void main() + { + omw_FragColor = omw_Texture2D(RT_Downsample, omw_TexCoord); + } + } + Now, if we ever run the `downsample2x` pass it will write to the target buffer instead of the default one assigned by the engine.