Skip to content

Commit

Permalink
[renderer] render scene exclusively to fbo
Browse files Browse the repository at this point in the history
  • Loading branch information
glassmancody committed Oct 31, 2023
1 parent bff4666 commit 7e9690e
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 395 deletions.
51 changes: 21 additions & 30 deletions apps/openmw/mwrender/npcanimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,46 +328,37 @@ namespace MWRender
{
osg::State* state = renderInfo.getState();

PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
PostProcessor* postProcessor = static_cast<PostProcessor*>(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<osg::GLExtensions>()->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<osg::GLExtensions>()->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<osg::StateSet> restore = bin->getStateSet();
bin->setStateSet(mStateSet);
bin->drawImplementation(renderInfo, previous);
bin->setStateSet(restore);
// depth accumulation pass
osg::ref_ptr<osg::StateSet> 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");
}
Expand Down
67 changes: 28 additions & 39 deletions apps/openmw/mwrender/pingpongcanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -77,27 +74,23 @@ namespace MWRender

size_t frameId = state.getFrameStamp()->getFrameNumber() % 2;

auto& bufferData = mBufferData[frameId];

const auto& data = bufferData.data;

std::vector<size_t> 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);
}

auto* resolveViewport = state.getCurrentViewport();

if (filtered.empty() || !bufferData.postprocessing)
if (filtered.empty() || !mPostprocessing)
{
state.pushStateSet(mFallbackStateSet);
state.apply();
Expand All @@ -108,7 +101,7 @@ namespace MWRender
state.apply();
}

state.applyTextureAttribute(0, bufferData.sceneTex);
state.applyTextureAttribute(0, mTextureScene);
resolveViewport->apply(state);

drawGeometry(renderInfo);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -150,23 +142,23 @@ 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<std::array<int, 2>, 3> buffers
= { { { GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT },
{ 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.
Expand All @@ -181,8 +173,7 @@ namespace MWRender

const unsigned int cid = state.getContextID();

const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo
= bufferData.destination ? bufferData.destination : nullptr;
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo = mDestinationFBO ? mDestinationFBO : nullptr;
unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0;

auto bindDestinationFbo = [&]() {
Expand All @@ -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();
Expand All @@ -231,15 +221,15 @@ 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]
->getAttachment(osg::Camera::COLOR_BUFFER0)
.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]
Expand All @@ -260,7 +250,6 @@ namespace MWRender
}

lastApplied = pass.mRenderTarget->getHandle(state.getContextID());
;
}
else if (pass.mResolve && index == filtered.back())
{
Expand Down
72 changes: 24 additions & 48 deletions apps/openmw/mwrender/pingpongcanvas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<osg::Texture> tex) { mBufferData[frameId].sceneTex = tex; }
void setMask(bool underwater, bool exterior);

void setLDRSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex)
{
mBufferData[frameId].sceneTexLDR = tex;
}
void setTextureScene(osg::ref_ptr<osg::Texture> tex) { mTextureScene = tex; }

void setDepthTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].depthTex = tex; }
void setTextureDepth(osg::ref_ptr<osg::Texture> tex) { mTextureDepth = tex; }

void setNormalsTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex)
{
mBufferData[frameId].normalsTex = tex;
}
void setTextureNormals(osg::ref_ptr<osg::Texture> 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<osg::Texture>& getSceneTexture(size_t frameId) const
{
return mBufferData[frameId].sceneTex;
}

void drawGeometry(osg::RenderInfo& renderInfo) const;
const osg::ref_ptr<osg::Texture>& 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<osg::Program> mFallbackProgram;
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;

struct BufferData
{
bool dirty = false;
bool hdr = false;
bool postprocessing = true;
osg::ref_ptr<osg::Texture> mTextureScene;
osg::ref_ptr<osg::Texture> mTextureDepth;
osg::ref_ptr<osg::Texture> mTextureNormals;

fx::DispatchArray data;
fx::FlagsType mask;

osg::ref_ptr<osg::FrameBufferObject> destination;

osg::ref_ptr<osg::Texture> sceneTex;
osg::ref_ptr<osg::Texture> depthTex;
osg::ref_ptr<osg::Texture> sceneTexLDR;
osg::ref_ptr<osg::Texture> normalsTex;
};

mutable std::array<BufferData, 2> mBufferData;
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
mutable bool mDirty = false;
mutable osg::ref_ptr<osg::Viewport> mRenderViewport;
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
mutable osg::ref_ptr<osg::FrameBufferObject> mDestinationFBO;
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
mutable LuminanceCalculator mLuminanceCalculator;
};
}

Expand Down
Loading

0 comments on commit 7e9690e

Please sign in to comment.