Refactor multiview to avoid littering OSG_HAS_MULTIVIEW and multiview-related uniforms around the code, keep them all in multiview.cpp.

LTO-timing^2
Mads Buvik Sandvei 3 years ago
parent aaaeed572a
commit b277fa48c7

@ -25,6 +25,7 @@
#include <components/settings/settings.hpp>
#include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/stereo/multiview.hpp>
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
@ -179,20 +180,6 @@ namespace MWRender
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
SceneUtil::setCameraClearDepth(camera);
#ifdef OSG_HAS_MULTIVIEW
if (shouldDoTextureArray())
{
auto* viewUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2);
auto* projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
viewUniform->setElement(0, osg::Matrix::identity());
viewUniform->setElement(1, osg::Matrix::identity());
projUniform->setElement(0, mPerspectiveMatrix);
projUniform->setElement(1, mPerspectiveMatrix);
mGroup->getOrCreateStateSet()->addUniform(viewUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
mGroup->getOrCreateStateSet()->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
#endif
camera->setNodeMask(Mask_RenderToTexture);
camera->addChild(mGroup);
};
@ -202,6 +189,9 @@ namespace MWRender
if(mCameraStateset)
camera->setStateSet(mCameraStateset);
camera->setViewMatrix(mViewMatrix);
if (shouldDoTextureArray())
Stereo::setMultiviewMatrices(mGroup->getOrCreateStateSet(), { mPerspectiveMatrix, mPerspectiveMatrix });
};
void addChild(osg::Node* node)

@ -702,16 +702,7 @@ void LocalMapRenderToTexture::setDefaults(osg::Camera* camera)
stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast<osg::Matrixf>(mProjectionMatrix)), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
if (Stereo::getMultiview())
{
auto* viewUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2);
auto* projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
viewUniform->setElement(0, osg::Matrix::identity());
viewUniform->setElement(1, osg::Matrix::identity());
projUniform->setElement(0, mProjectionMatrix);
projUniform->setElement(1, mProjectionMatrix);
stateset->addUniform(viewUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
Stereo::setMultiviewMatrices(stateset, { mProjectionMatrix, mProjectionMatrix });
// assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG)

@ -67,25 +67,8 @@ namespace MWRender
static void attachCloneOfTemplate(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex)
{
switch (tex->getTextureTarget())
{
case GL_TEXTURE_2D:
{
auto* tex2d = new osg::Texture2D(*static_cast<osg::Texture2D*>(tex));
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
}
break;
case GL_TEXTURE_2D_ARRAY:
{
#ifdef OSG_HAS_MULTIVIEW
auto* tex2dArray = new osg::Texture2DArray(*static_cast<osg::Texture2DArray*>(tex));
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0));
#endif
}
break;
default:
throw std::logic_error("Invalid texture type received");
}
osg::ref_ptr<osg::Texture> clone = static_cast<osg::Texture*>(tex->clone(osg::CopyOp::SHALLOW_COPY));
fbo->setAttachment(component, Stereo::createMultiviewCompatibleAttachment(clone));
}
void PingPongCanvas::drawImplementation(osg::RenderInfo& renderInfo) const

@ -9,10 +9,6 @@
#include <osg/Texture3D>
#include <osg/Texture2DArray>
#ifdef OSG_HAS_MULTIVIEW
#include <osg/Texture2DMultisampleArray>
#endif
#include <components/settings/settings.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/color.hpp>
@ -75,53 +71,6 @@ namespace
}
};
static void setTextureSize(osg::Texture* tex, int w, int h)
{
switch (tex->getTextureTarget())
{
case GL_TEXTURE_2D:
static_cast<osg::Texture2D*>(tex)->setTextureSize(w, h);
break;
case GL_TEXTURE_2D_ARRAY:
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
break;
case GL_TEXTURE_2D_MULTISAMPLE:
static_cast<osg::Texture2DMultisample*>(tex)->setTextureSize(w, h);
break;
#ifdef OSG_HAS_MULTIVIEW
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
static_cast<osg::Texture2DMultisampleArray*>(tex)->setTextureSize(w, h, 2);
break;
#endif
default:
throw std::logic_error("Invalid texture type received");
}
}
static void setAttachment(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex)
{
switch (tex->getTextureTarget())
{
case GL_TEXTURE_2D:
{
auto* tex2d = static_cast<osg::Texture2D*>(tex);
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
}
break;
case GL_TEXTURE_2D_ARRAY:
{
#ifdef OSG_HAS_MULTIVIEW
auto* tex2dArray = static_cast<osg::Texture2DArray*>(tex);
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0));
#endif
}
break;
default:
throw std::logic_error("Invalid texture type received");
}
}
enum class Usage
{
RENDER_BUFFER,
@ -136,35 +85,7 @@ namespace
return osg::FrameBufferAttachment(attachment);
}
osg::FrameBufferAttachment attachment;
#ifdef OSG_HAS_MULTIVIEW
if (Stereo::getMultiview())
{
if (samples > 1)
{
attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisampleArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
}
else
{
attachment = osg::FrameBufferAttachment(new osg::Texture2DArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
}
}
else
#endif
{
if (samples > 1)
{
attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisample());
}
else
{
attachment = osg::FrameBufferAttachment(new osg::Texture2D());
}
}
osg::Texture* texture = attachment.getTexture();
setTextureSize(texture, width, height);
auto texture = Stereo::createMultiviewCompatibleTexture(width, height, samples);
texture->setSourceFormat(template_->getSourceFormat());
texture->setSourceType(template_->getSourceType());
texture->setInternalFormat(template_->getInternalFormat());
@ -173,7 +94,7 @@ namespace
texture->setWrap(osg::Texture::WRAP_S, template_->getWrap(osg::Texture2D::WRAP_S));
texture->setWrap(osg::Texture::WRAP_T, template_->getWrap(osg::Texture2D::WRAP_T));
return attachment;
return Stereo::createMultiviewCompatibleAttachment(texture);
}
}
@ -547,15 +468,15 @@ namespace MWRender
if (!tex)
continue;
setTextureSize(tex, width, height);
Stereo::setMultiviewCompatibleTextureSize(tex, width, height);
tex->dirtyTextureObject();
}
fbos[FBO_Primary] = new osg::FrameBufferObject;
setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER0, textures[Tex_Scene]);
fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
if (mNormals && mNormalsSupported)
setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER1, textures[Tex_Normal]);
setAttachment(fbos[FBO_Primary], osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_Depth]);
fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
fbos[FBO_Primary]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Depth]));
fbos[FBO_FirstPerson] = new osg::FrameBufferObject;
@ -581,20 +502,20 @@ namespace MWRender
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, colorRB);
fbos[FBO_Intercept] = new osg::FrameBufferObject;
setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]);
setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]);
fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
}
else
{
setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]);
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
if (mNormals && mNormalsSupported)
setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]);
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
}
if (textures[Tex_OpaqueDepth])
{
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
setAttachment(fbos[FBO_OpaqueDepth], osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_OpaqueDepth]);
fbos[FBO_OpaqueDepth]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, Stereo::createMultiviewCompatibleAttachment(textures[Tex_OpaqueDepth]));
}
#ifdef __APPLE__
@ -799,7 +720,7 @@ namespace MWRender
else
texture = new osg::Texture2D;
}
setTextureSize(texture, width, height);
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
texture->setSourceFormat(GL_RGBA);
texture->setSourceType(GL_UNSIGNED_BYTE);
texture->setInternalFormat(GL_RGBA);

@ -615,9 +615,7 @@ namespace MWRender
protected:
void setDefaults(osg::StateSet* stateset) override
{
if (Stereo::getMultiview())
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2), osg::StateAttribute::OVERRIDE);
else
if (!Stereo::getMultiview())
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrix"), osg::StateAttribute::OVERRIDE);
}
@ -626,7 +624,7 @@ namespace MWRender
{
if (Stereo::getMultiview())
{
auto* projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView");
std::array<osg::Matrix, 2> projectionMatrices;
auto& sm = Stereo::Manager::instance();
for (int view : {0, 1})
@ -636,8 +634,10 @@ namespace MWRender
for (int col : {0, 1, 2})
viewOffsetMatrix(3, col) = 0;
projectionMatrixMultiViewUniform->setElement(view, viewOffsetMatrix * projectionMatrix);
projectionMatrices[view] = viewOffsetMatrix * projectionMatrix;
}
Stereo::setMultiviewMatrices(stateset, projectionMatrices);
}
}
void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* /*cv*/) override

@ -4,10 +4,6 @@
#include <osg/Texture2D>
#include <osg/Texture2DArray>
#ifdef OSG_HAS_MULTIVIEW
#include <osg/Texture2DMultisampleArray>
#endif
#include <osgUtil/RenderStage>
#include <components/shader/shadermanager.hpp>
@ -70,14 +66,11 @@ namespace MWRender
if (Stereo::getMultiview())
{
if (!mMultiviewDepthResolveLeftSource[frameId])
setupMultiviewDepthResolveBuffers(frameId);
mMultiviewDepthResolveLeftTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
mMultiviewDepthResolveLeftSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
mMultiviewDepthResolveRightTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
mMultiviewDepthResolveRightSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
if (!mMultiviewResolve[frameId])
{
mMultiviewResolve[frameId] = std::make_unique<Stereo::MultiviewFramebufferResolve>(msaaFbo ? msaaFbo : fbo, opaqueFbo, GL_DEPTH_BUFFER_BIT);
}
mMultiviewResolve[frameId]->resolveImplementation(state);
}
else
{
@ -107,42 +100,8 @@ namespace MWRender
void TransparentDepthBinCallback::dirtyFrame(int frameId)
{
mMultiviewDepthResolveLeftSource[frameId] = mMultiviewDepthResolveRightSource[frameId] = nullptr;
mMultiviewDepthResolveLeftTarget[frameId] = mMultiviewDepthResolveRightTarget[frameId] = nullptr;
}
osg::FrameBufferAttachment makeSingleLayerAttachmentFromMultilayerAttachment(osg::FrameBufferAttachment attachment, int layer)
{
osg::Texture* tex = attachment.getTexture();
if (tex->getTextureTarget() == GL_TEXTURE_2D_ARRAY)
return osg::FrameBufferAttachment(static_cast<osg::Texture2DArray*>(tex), layer, 0);
#ifdef OSG_HAS_MULTIVIEW
if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
return osg::FrameBufferAttachment(static_cast<osg::Texture2DMultisampleArray*>(tex), layer, 0);
#endif
Log(Debug::Error) << "Attempted to extract a layer from an unlayered texture";
return osg::FrameBufferAttachment();
}
void TransparentDepthBinCallback::setupMultiviewDepthResolveBuffers(int frameId)
{
const osg::FrameBufferObject::BufferComponent component = osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER;
const auto& sourceFbo = mMsaaFbo[frameId] ? mMsaaFbo[frameId] : mFbo[frameId];
const auto& sourceAttachment = sourceFbo->getAttachment(component);
mMultiviewDepthResolveLeftSource[frameId] = new osg::FrameBufferObject;
mMultiviewDepthResolveLeftSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 0));
mMultiviewDepthResolveRightSource[frameId] = new osg::FrameBufferObject;
mMultiviewDepthResolveRightSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 1));
const auto& targetFbo = mOpaqueFbo[frameId];
const auto& targetAttachment = targetFbo->getAttachment(component);
mMultiviewDepthResolveLeftTarget[frameId] = new osg::FrameBufferObject;
mMultiviewDepthResolveLeftTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 0));
mMultiviewDepthResolveRightTarget[frameId] = new osg::FrameBufferObject;
mMultiviewDepthResolveRightTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 1));
if (mMultiviewResolve[frameId])
mMultiviewResolve[frameId]->dirty();
}
}

@ -15,6 +15,11 @@ namespace Shader
class ShaderManager;
}
namespace Stereo
{
class MultiviewFramebufferResolve;
}
namespace MWRender
{
class TransparentDepthBinCallback : public osgUtil::RenderBin::DrawCallback
@ -24,16 +29,12 @@ namespace MWRender
void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override;
void dirtyFrame(int frameId);
void setupMultiviewDepthResolveBuffers(int frameId);
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mOpaqueFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftSource;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightSource;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftTarget;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightTarget;
std::array<std::unique_ptr<Stereo::MultiviewFramebufferResolve>, 2> mMultiviewResolve;
private:
osg::ref_ptr<osg::StateSet> mStateSet;

@ -200,21 +200,20 @@ namespace SceneUtil
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER))
vdd->mDepthTexture = camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._texture;
#ifdef OSG_HAS_MULTIVIEW
if (shouldDoTextureArray())
{
// Create any buffer attachments not added in setDefaults
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)
{
vdd->mColorTexture = createTextureArray(mColorBufferInternalFormat);
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps, mSamples);
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps);
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples);
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps);
}
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0)
{
vdd->mDepthTexture = createTextureArray(mDepthBufferInternalFormat);
camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, false, mSamples);
camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), false, mSamples);
}
if (shouldDoTextureView())
@ -226,7 +225,6 @@ namespace SceneUtil
}
}
else
#endif
{
// Create any buffer attachments not added in setDefaults
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)

@ -27,31 +27,32 @@
#include <components/settings/settings.hpp>
#include <components/stereo/multiview.hpp>
#include <components/misc/stringops.hpp>
#include "frustum.hpp"
namespace Stereo
{
#ifdef OSG_HAS_MULTIVIEW
struct MultiviewFrustumCallback final : public osg::CullSettings::InitialFrustumCallback
struct MultiviewFrustumCallback final : public Stereo::InitialFrustumCallback
{
MultiviewFrustumCallback(StereoFrustumManager* sfm)
: mSfm(sfm)
MultiviewFrustumCallback(StereoFrustumManager* sfm, osg::Camera* camera)
: Stereo::InitialFrustumCallback(camera)
, mSfm(sfm)
{
}
void setInitialFrustum(osg::CullStack& cullStack, osg::Polytope& frustum) const override
void setInitialFrustum(osg::CullStack& cullStack, osg::BoundingBoxd& bb, bool& nearCulling, bool& farCulling) const override
{
auto cm = cullStack.getCullingMode();
bool nearCulling = !!(cm & osg::CullSettings::NEAR_PLANE_CULLING);
bool farCulling = !!(cm & osg::CullSettings::FAR_PLANE_CULLING);
frustum.setToBoundingBox(mSfm->boundingBox(), nearCulling, farCulling);
nearCulling = !!(cm & osg::CullSettings::NEAR_PLANE_CULLING);
farCulling = !!(cm & osg::CullSettings::FAR_PLANE_CULLING);
bb = mSfm->boundingBox();
}
StereoFrustumManager* mSfm;
};
#endif
struct ShadowFrustumCallback final : public SceneUtil::MWShadowTechnique::CustomFrustumCallback
{
@ -95,14 +96,10 @@ namespace Stereo
: mCamera(camera)
, mShadowTechnique(nullptr)
, mShadowFrustumCallback(nullptr)
, mMultiview(Stereo::getMultiview())
{
if (mMultiview)
if (Stereo::getMultiview())
{
#ifdef OSG_HAS_MULTIVIEW
mMultiviewFrustumCallback = new MultiviewFrustumCallback(this);
mCamera->setInitialFrustumCallback(mMultiviewFrustumCallback);
#endif
mMultiviewFrustumCallback = std::make_unique<MultiviewFrustumCallback>(this, camera);
}
if (Settings::Manager::getBool("shared shadow maps", "Stereo"))
@ -118,13 +115,6 @@ namespace Stereo
StereoFrustumManager::~StereoFrustumManager()
{
if (mMultiview)
{
#ifdef OSG_HAS_MULTIVIEW
mCamera->setInitialFrustumCallback(nullptr);
#endif
}
if (mShadowTechnique)
mShadowTechnique->setCustomFrustumCallback(nullptr);
}

@ -38,10 +38,7 @@ namespace SceneUtil
namespace Stereo
{
#ifdef OSG_HAS_MULTIVIEW
struct MultiviewFrustumCallback;
#endif
struct ShadowFrustumCallback;
void joinBoundingBoxes(const osg::Matrix& masterProjection, const osg::Matrix& slaveProjection, osg::BoundingBoxd& bb);
@ -64,13 +61,10 @@ namespace Stereo
osg::ref_ptr<osg::Camera> mCamera;
osg::ref_ptr<SceneUtil::MWShadowTechnique> mShadowTechnique;
osg::ref_ptr<ShadowFrustumCallback> mShadowFrustumCallback;
bool mMultiview;
std::map< osgUtil::CullVisitor*, osgUtil::CullVisitor*> mSharedFrustums;
osg::BoundingBoxd mBoundingBox;
#ifdef OSG_HAS_MULTIVIEW
osg::ref_ptr<MultiviewFrustumCallback> mMultiviewFrustumCallback;
#endif
std::unique_ptr<MultiviewFrustumCallback> mMultiviewFrustumCallback;
};
}

@ -3,6 +3,7 @@
#include <osg/FrameBufferObject>
#include <osg/GLExtensions>
#include <osg/Texture2D>
#include <osg/Texture2DMultisample>
#include <osg/Texture2DArray>
#include <osgUtil/RenderStage>
#include <osgUtil/CullVisitor>
@ -337,6 +338,133 @@ namespace Stereo
#endif
}
void setMultiviewMatrices(osg::StateSet* stateset, const std::array<osg::Matrix, 2>& projection, bool createInverseMatrices)
{
auto* projUniform = stateset->getUniform("projectionMatrixMultiView");
if (!projUniform)
{
projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
stateset->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
projUniform->setElement(0, projection[0]);
projUniform->setElement(1, projection[1]);
if (createInverseMatrices)
{
auto* invUniform = stateset->getUniform("invProjectionMatrixMultiView");
if (!invUniform)
{
invUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2);
stateset->addUniform(invUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
invUniform->setElement(0, osg::Matrix::inverse(projection[0]));
invUniform->setElement(1, osg::Matrix::inverse(projection[1]));
}
}
void setMultiviewCompatibleTextureSize(osg::Texture* tex, int w, int h)
{
switch (tex->getTextureTarget())
{
case GL_TEXTURE_2D:
static_cast<osg::Texture2D*>(tex)->setTextureSize(w, h);
break;
case GL_TEXTURE_2D_ARRAY:
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
break;
case GL_TEXTURE_2D_MULTISAMPLE:
static_cast<osg::Texture2DMultisample*>(tex)->setTextureSize(w, h);
break;
#ifdef OSG_HAS_MULTIVIEW
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
static_cast<osg::Texture2DMultisampleArray*>(tex)->setTextureSize(w, h, 2);
break;
#endif
default:
throw std::logic_error("Invalid texture type received");
}
}
osg::ref_ptr<osg::Texture> createMultiviewCompatibleTexture(int width, int height, int samples)
{
#ifdef OSG_HAS_MULTIVIEW
if (Stereo::getMultiview())
{
if (samples > 1)
{
auto tex = new osg::Texture2DMultisampleArray();
tex->setTextureSize(width, height, 2);
tex->setNumSamples(samples);
return tex;
}
else
{
auto tex = new osg::Texture2DArray();
tex->setTextureSize(width, height, 2);
return tex;
}
}
else
#endif
{
if (samples > 1)
{
auto tex = new osg::Texture2DMultisample();
tex->setTextureSize(width, height);
tex->setNumSamples(samples);
return tex;
}
else
{
auto tex = new osg::Texture2D();
tex->setTextureSize(width, height);
return tex;
}
}
}
osg::FrameBufferAttachment createMultiviewCompatibleAttachment(osg::Texture* tex)
{
switch (tex->getTextureTarget())
{
case GL_TEXTURE_2D:
{
auto* tex2d = static_cast<osg::Texture2D*>(tex);
return osg::FrameBufferAttachment(tex2d);
}
case GL_TEXTURE_2D_MULTISAMPLE:
{
auto* tex2dMsaa = static_cast<osg::Texture2DMultisample*>(tex);
return osg::FrameBufferAttachment(tex2dMsaa);
}
#ifdef OSG_HAS_MULTIVIEW
case GL_TEXTURE_2D_ARRAY:
{
auto* tex2dArray = static_cast<osg::Texture2DArray*>(tex);
return osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
}
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
{
auto* tex2dMsaaArray = static_cast<osg::Texture2DMultisampleArray*>(tex);
return osg::FrameBufferAttachment(tex2dMsaaArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
}
#endif
default:
throw std::logic_error("Invalid texture type received");
}
}
unsigned int osgFaceControlledByMultiviewShader()
{
#ifdef OSG_HAS_MULTIVIEW
return osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER;
#else
return 0;
#endif
}
class UpdateRenderStagesCallback : public SceneUtil::NodeCallback<UpdateRenderStagesCallback, osg::Node*, osgUtil::CullVisitor*>
{
public:
@ -558,4 +686,111 @@ namespace Stereo
textureArray->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
return textureArray;
}
osg::FrameBufferAttachment makeSingleLayerAttachmentFromMultilayerAttachment(osg::FrameBufferAttachment attachment, int layer)
{
osg::Texture* tex = attachment.getTexture();
if (tex->getTextureTarget() == GL_TEXTURE_2D_ARRAY)
return osg::FrameBufferAttachment(static_cast<osg::Texture2DArray*>(tex), layer, 0);
#ifdef OSG_HAS_MULTIVIEW
if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
return osg::FrameBufferAttachment(static_cast<osg::Texture2DMultisampleArray*>(tex), layer, 0);
#endif
Log(Debug::Error) << "Attempted to extract a layer from an unlayered texture";
return osg::FrameBufferAttachment();
}
MultiviewFramebufferResolve::MultiviewFramebufferResolve(osg::FrameBufferObject* msaaFbo, osg::FrameBufferObject* resolveFbo, GLbitfield blitMask)
: mResolveFbo(resolveFbo)
, mMsaaFbo(msaaFbo)
, mBlitMask(blitMask)
{
}
void MultiviewFramebufferResolve::resolveImplementation(osg::State& state)
{
if (mDirtyLayers)
setupLayers();
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
for (int view : {0, 1})
{
mResolveLayers[view]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
mMsaaLayers[view]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
}
void MultiviewFramebufferResolve::setupLayers()
{
mDirtyLayers = false;
std::vector<osg::FrameBufferObject::BufferComponent> components;
if (mBlitMask & GL_DEPTH_BUFFER_BIT)
components.push_back(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER);
if (mBlitMask & GL_COLOR_BUFFER_BIT)
components.push_back(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER);
mMsaaLayers = { new osg::FrameBufferObject, new osg::FrameBufferObject };
mResolveLayers = { new osg::FrameBufferObject, new osg::FrameBufferObject };
for (auto component : components)
{
const auto& msaaAttachment = mMsaaFbo->getAttachment(component);
mMsaaLayers[0]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(msaaAttachment, 0));
mMsaaLayers[1]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(msaaAttachment, 1));
const auto& resolveAttachment = mResolveFbo->getAttachment(component);
mResolveLayers[0]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(resolveAttachment, 0));
mResolveLayers[1]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(resolveAttachment, 1));
mWidth = msaaAttachment.getTexture()->getTextureWidth();
mHeight = msaaAttachment.getTexture()->getTextureHeight();
}
}
#ifdef OSG_HAS_MULTIVIEW
namespace
{
struct MultiviewFrustumCallback final : public osg::CullSettings::InitialFrustumCallback
{
MultiviewFrustumCallback(Stereo::InitialFrustumCallback* ifc)
: mIfc(ifc)
{
}
void setInitialFrustum(osg::CullStack& cullStack, osg::Polytope& frustum) const override
{
bool nearCulling = false;
bool farCulling = false;
osg::BoundingBoxd bb;
mIfc->setInitialFrustum(cullStack, bb, nearCulling, farCulling);
frustum.setToBoundingBox(bb, nearCulling, farCulling);
}
Stereo::InitialFrustumCallback* mIfc;
};
}
#endif
InitialFrustumCallback::InitialFrustumCallback(osg::Camera* camera)
: mCamera(camera)
{
#ifdef OSG_HAS_MULTIVIEW
camera->setInitialFrustumCallback(new MultiviewFrustumCallback(this));
#endif
}
InitialFrustumCallback::~InitialFrustumCallback()
{
#ifdef OSG_HAS_MULTIVIEW
osg::ref_ptr<osg::Camera> camera;
if(mCamera.lock(camera))
camera->setInitialFrustumCallback(nullptr);
#endif
}
}

@ -4,6 +4,7 @@
#include <osg/ref_ptr>
#include <osg/GL>
#include <osg/Camera>
#include <osg/FrameBufferObject>
#include <array>
#include <memory>
@ -40,9 +41,6 @@ namespace Stereo
//! Creates a Texture2D as a texture view into a Texture2DArray
osg::ref_ptr<osg::Texture2D> createTextureView_Texture2DFromTexture2DArray(osg::Texture2DArray* textureArray, int layer);
//! Sets up a draw callback on the render stage that performs the MSAA resolve operation
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage);
//! Class that manages the specifics of GL_OVR_Multiview aware framebuffers, separating the layers into separate framebuffers, and disabling
class MultiviewFramebuffer
{
@ -86,6 +84,61 @@ namespace Stereo
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
};
//! Sets up a draw callback on the render stage that performs the MSAA resolve operation
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage);
//! Sets up or updates multiview matrices for the given stateset
void setMultiviewMatrices(osg::StateSet* stateset, const std::array<osg::Matrix, 2>& projection, bool createInverseMatrices = false);
//! Sets the width/height of a texture by first down-casting it to the appropriate type. Sets depth to 2 always for Texture2DArray and Texture2DMultisampleArray.
void setMultiviewCompatibleTextureSize(osg::Texture* tex, int w, int h);
//! Creates a texture (Texture2D, Texture2DMultisample, Texture2DArray, or Texture2DMultisampleArray) based on multiview settings and sample count.
osg::ref_ptr<osg::Texture> createMultiviewCompatibleTexture(int width, int height, int samples);
//! Returns a framebuffer attachment from the texture, returning a multiview attachment if the texture is one of Texture2DArray or Texture2DMultisampleArray
osg::FrameBufferAttachment createMultiviewCompatibleAttachment(osg::Texture* tex);
//! If OSG has multiview, returns the magic number used to tell OSG to create a multiview attachment. Otherwise returns 0.
unsigned int osgFaceControlledByMultiviewShader();
//! Implements resolving a multisamples multiview framebuffer. Does not automatically reflect changes to the fbo attachments, must call dirty() when the fbo attachments change.
class MultiviewFramebufferResolve
{
public:
MultiviewFramebufferResolve(osg::FrameBufferObject* msaaFbo, osg::FrameBufferObject* resolveFbo, GLbitfield blitMask);
void resolveImplementation(osg::State& state);
void dirty() { mDirtyLayers = true; }
const osg::FrameBufferObject* resolveFbo() const { return mResolveFbo; };
const osg::FrameBufferObject* msaaFbo() const { return mMsaaFbo; };
private:
void setupLayers();
osg::ref_ptr<osg::FrameBufferObject> mResolveFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mResolveLayers{};
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaLayers{};
GLbitfield mBlitMask;
bool mDirtyLayers = true;
int mWidth = -1;
int mHeight = -1;
};
//! Wrapper for osg::CullSettings::InitialFrustumCallback, to avoid exposing osg multiview interfaces outside of multiview.cpp
struct InitialFrustumCallback
{
InitialFrustumCallback(osg::Camera* camera);
virtual ~InitialFrustumCallback();
virtual void setInitialFrustum(osg::CullStack& cullStack, osg::BoundingBoxd& bb, bool& nearCulling, bool& farCulling) const = 0;
osg::observer_ptr<osg::Camera> mCamera;
};
}
#endif

@ -97,7 +97,6 @@ namespace Stereo
protected:
virtual void setDefaults(osg::StateSet* stateset)
{
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2));
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2));
}
@ -195,8 +194,8 @@ namespace Stereo
mEyeResolutionOverride = eyeResolution;
mEyeResolutionOverriden = true;
if (mMultiviewFramebuffer)
updateStereoFramebuffer();
//if (mMultiviewFramebuffer)
// updateStereoFramebuffer();
}
void Manager::screenResolutionChanged()
@ -302,14 +301,14 @@ namespace Stereo
void Manager::updateStereoFramebuffer()
{
//VR-TODO: in VR, still need to have this framebuffer attached before the postprocessor is created
auto samples = Settings::Manager::getInt("antialiasing", "Video");
auto eyeRes = eyeResolution();
//auto samples = Settings::Manager::getInt("antialiasing", "Video");
//auto eyeRes = eyeResolution();
//if (mMultiviewFramebuffer)
// mMultiviewFramebuffer->detachFrom(mMainCamera);
mMultiviewFramebuffer = std::make_shared<MultiviewFramebuffer>(static_cast<int>(eyeRes.x()), static_cast<int>(eyeRes.y()), samples);
mMultiviewFramebuffer->attachColorComponent(SceneUtil::Color::colorSourceFormat(), SceneUtil::Color::colorSourceType(), SceneUtil::Color::colorInternalFormat());
mMultiviewFramebuffer->attachDepthComponent(SceneUtil::AutoDepth::depthSourceFormat(), SceneUtil::AutoDepth::depthSourceType(), SceneUtil::AutoDepth::depthInternalFormat());
//mMultiviewFramebuffer = std::make_shared<MultiviewFramebuffer>(static_cast<int>(eyeRes.x()), static_cast<int>(eyeRes.y()), samples);
//mMultiviewFramebuffer->attachColorComponent(SceneUtil::Color::colorSourceFormat(), SceneUtil::Color::colorSourceType(), SceneUtil::Color::colorInternalFormat());
//mMultiviewFramebuffer->attachDepthComponent(SceneUtil::AutoDepth::depthSourceFormat(), SceneUtil::AutoDepth::depthSourceType(), SceneUtil::AutoDepth::depthInternalFormat());
//mMultiviewFramebuffer->attachTo(mMainCamera);
}
@ -376,17 +375,12 @@ namespace Stereo
void Manager::updateMultiviewStateset(osg::StateSet* stateset)
{
// Update stereo uniforms
auto * projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView");
auto * invProjectionMatrixMultiViewUniform = stateset->getUniform("invProjectionMatrixMultiView");
std::array<osg::Matrix, 2> projectionMatrices;
for (int view : {0, 1})
{
auto projectionMatrix = computeEyeViewOffset(view) * computeEyeProjection(view, SceneUtil::AutoDepth::isReversed());
auto invProjectionMatrix = osg::Matrix::inverse(projectionMatrix);
projectionMatrixMultiViewUniform->setElement(view, projectionMatrix);
invProjectionMatrixMultiViewUniform->setElement(view, invProjectionMatrix);
}
projectionMatrices[view] = computeEyeViewOffset(view) * computeEyeProjection(view, SceneUtil::AutoDepth::isReversed());
Stereo::setMultiviewMatrices(stateset, projectionMatrices, true);
}
void Manager::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb)

Loading…
Cancel
Save