diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 953e3076b3..716a087d02 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "../widget/scenetoolmode.hpp" @@ -76,6 +77,8 @@ namespace CSVRender = new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height()); mWidget->setGraphicsWindowEmbedded(window); + mRenderer->setRealizeOperation(new SceneUtil::GetGLExtensionsOperation()); + int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt(); mRenderer->setRunMaxFrameRate(frameRateLimit); mRenderer->setUseConfigureAffinity(false); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 75687ff281..49833040d6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -600,6 +601,7 @@ void OMW::Engine::createWindow() mViewer->setRealizeOperation(realizeOperations); osg::ref_ptr identifyOp = new IdentifyOpenGLOperation(); realizeOperations->add(identifyOp); + realizeOperations->add(new SceneUtil::GetGLExtensionsOperation()); if (Debug::shouldDebugOpenGL()) realizeOperations->add(new Debug::EnableGLDebugOperation()); @@ -780,13 +782,13 @@ void OMW::Engine::prepareEngine() // gui needs our shaders path before everything else mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders"); - osg::ref_ptr exts = osg::GLExtensions::Get(0, false); - bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f); + osg::GLExtensions& exts = SceneUtil::getGLExtensions(); + bool shadersSupported = exts.glslLanguageVersion >= 1.2f; #if OSG_VERSION_LESS_THAN(3, 6, 6) // hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028 - if (exts) - exts->glRenderbufferStorageMultisampleCoverageNV = nullptr; + if (!osg::isGLExtensionSupported(exts.contextID, "NV_framebuffer_multisample_coverage")) + exts.glRenderbufferStorageMultisampleCoverageNV = nullptr; #endif osg::ref_ptr guiRoot = new osg::Group; diff --git a/apps/openmw/mwrender/ripples.cpp b/apps/openmw/mwrender/ripples.cpp index 94135eeec5..28427c3671 100644 --- a/apps/openmw/mwrender/ripples.cpp +++ b/apps/openmw/mwrender/ripples.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "../mwworld/ptr.hpp" @@ -43,9 +44,9 @@ namespace MWRender mUseCompute = false; #else constexpr float minimumGLVersionRequiredForCompute = 4.4; - osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); - mUseCompute = exts->glVersion >= minimumGLVersionRequiredForCompute - && exts->glslLanguageVersion >= minimumGLVersionRequiredForCompute; + osg::GLExtensions& exts = SceneUtil::getGLExtensions(); + mUseCompute = exts.glVersion >= minimumGLVersionRequiredForCompute + && exts.glslLanguageVersion >= minimumGLVersionRequiredForCompute; #endif if (mUseCompute) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9868a8fdf9..01efcd7c05 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -143,7 +143,7 @@ add_component_dir (sceneutil lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt screencapture depth color riggeometryosgaextension extradata unrefqueue lightcommon lightingmethod clearcolor - cullsafeboundsvisitor keyframe nodecallback textkeymap + cullsafeboundsvisitor keyframe nodecallback textkeymap glextensions ) add_component_dir (nif diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 26fd60d7ea..09c7048059 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -65,12 +66,13 @@ namespace Resource case (GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case (GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { - osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); - if (exts - && !exts->isTextureCompressionS3TCSupported + if (!SceneUtil::glExtensionsReady()) + return true; // hashtag yolo (CS might not have context when loading assets) + osg::GLExtensions& exts = SceneUtil::getGLExtensions(); + if (!exts.isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a // patch to OSG. - && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) + && !osg::isGLExtensionSupported(exts.contextID, "GL_S3_s3tc")) { return false; } diff --git a/components/sceneutil/depth.cpp b/components/sceneutil/depth.cpp index 738fa93dd8..5232d321dc 100644 --- a/components/sceneutil/depth.cpp +++ b/components/sceneutil/depth.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace SceneUtil @@ -116,8 +117,7 @@ namespace SceneUtil if (Settings::camera().mReverseZ) { - osg::ref_ptr exts = osg::GLExtensions::Get(0, false); - if (exts && exts->isClipControlSupported) + if (SceneUtil::getGLExtensions().isClipControlSupported) { enableReverseZ = true; Log(Debug::Info) << "Using reverse-z depth buffer"; diff --git a/components/sceneutil/glextensions.cpp b/components/sceneutil/glextensions.cpp new file mode 100644 index 0000000000..3a14dab8ed --- /dev/null +++ b/components/sceneutil/glextensions.cpp @@ -0,0 +1,60 @@ +#include "glextensions.hpp" + +#include + +namespace SceneUtil +{ + namespace + { + std::set> sGLExtensions; + + class GLExtensionsObserver : public osg::Observer + { + public: + static GLExtensionsObserver sInstance; + + ~GLExtensionsObserver() override + { + for (auto& ptr : sGLExtensions) + { + osg::ref_ptr ref; + if (ptr.lock(ref)) + ref->removeObserver(this); + } + } + + void objectDeleted(void* referenced) override + { + sGLExtensions.erase(static_cast(referenced)); + } + }; + + // construct after sGLExtensions so this gets destroyed first. + GLExtensionsObserver GLExtensionsObserver::sInstance{}; + } + + bool glExtensionsReady() + { + return !sGLExtensions.empty(); + } + + osg::GLExtensions& getGLExtensions() + { + if (sGLExtensions.empty()) + throw std::runtime_error( + "GetGLExtensionsOperation was not used when the current context was created or there is no current " + "context"); + return **sGLExtensions.begin(); + } + + GetGLExtensionsOperation::GetGLExtensionsOperation() + : GraphicsOperation("GetGLExtensionsOperation", false) + { + } + + void GetGLExtensionsOperation::operator()(osg::GraphicsContext* graphicsContext) + { + auto [itr, _] = sGLExtensions.emplace(graphicsContext->getState()->get()); + (*itr)->addObserver(&GLExtensionsObserver::sInstance); + } +} diff --git a/components/sceneutil/glextensions.hpp b/components/sceneutil/glextensions.hpp new file mode 100644 index 0000000000..05e7f715c1 --- /dev/null +++ b/components/sceneutil/glextensions.hpp @@ -0,0 +1,21 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_GLEXTENSIONS_H +#define OPENMW_COMPONENTS_SCENEUTIL_GLEXTENSIONS_H + +#include +#include + +namespace SceneUtil +{ + bool glExtensionsReady(); + osg::GLExtensions& getGLExtensions(); + + class GetGLExtensionsOperation : public osg::GraphicsOperation + { + public: + GetGLExtensionsOperation(); + + void operator()(osg::GraphicsContext* graphicsContext) override; + }; +} + +#endif diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 8f7304416b..c76f0b6b5c 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -824,7 +825,7 @@ namespace SceneUtil , mPointLightFadeEnd(0.f) , mPointLightFadeStart(0.f) { - osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); + osg::GLExtensions* exts = SceneUtil::glExtensionsReady() ? &SceneUtil::getGLExtensions() : nullptr; bool supportsUBO = exts && exts->isUniformBufferObjectSupported; bool supportsGPU4 = exts && exts->isGpuShader4Supported; diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index d0c270971a..d1553cc8d8 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -30,6 +30,7 @@ #include #include +#include "glextensions.hpp" #include "shadowsbin.hpp" namespace { @@ -920,8 +921,7 @@ void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & sh // This can't be part of the constructor as OSG mandates that there be a trivial constructor available osg::ref_ptr castingVertexShader = shaderManager.getShader("shadowcasting.vert"); - osg::ref_ptr exts = osg::GLExtensions::Get(0, false); - std::string useGPUShader4 = exts && exts->isGpuShader4Supported ? "1" : "0"; + std::string useGPUShader4 = SceneUtil::getGLExtensions().isGpuShader4Supported ? "1" : "0"; for (int alphaFunc = GL_NEVER; alphaFunc <= GL_ALWAYS; ++alphaFunc) { auto& program = _castingPrograms[alphaFunc - GL_NEVER]; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index e281f64448..7bce9de2a6 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -676,8 +677,7 @@ namespace Shader defineMap["adjustCoverage"] = "1"; // Preventing alpha tested stuff shrinking as lower mip levels are used requires knowing the texture size - osg::ref_ptr exts = osg::GLExtensions::Get(0, false); - if (exts && exts->isGpuShader4Supported) + if (SceneUtil::getGLExtensions().isGpuShader4Supported) defineMap["useGPUShader4"] = "1"; // We could fall back to a texture size uniform if EXT_gpu_shader4 is missing }