OGRECave / ogre

scene-oriented, flexible 3D engine (C++, Python, C#, Java)
https://ogrecave.github.io/ogre/
MIT License
3.85k stars 959 forks source link

Potential leak with techniques returned in Ogre::MaterialManager::Listener #3084

Closed fbridault closed 3 months ago

fbridault commented 3 months ago

System Information

Detailed description

I recently faced a big memory leak in sight. I realized that this is a regression in versions superior at least to 1.12.10. In Ogre::MaterialManager::Listener::handleSchemeNotFound, we create new techniques. These techniques are added in the "best" techniques list when the Material::compile() is called. However, in my case, the object is not visible, thus we never pass in the Ogre::RenderQueue::AddRenderable() function that triggers the material compile (via touch()). If the object is not visible, you will ask me why the material listener is called in the first place. Actually, this is because it is accumulated in the shadow render pass (though we don't use the feature at all, but that's another topic). What happens then, is that the Material manager keeps thinking that the technique is missing for the given scheme, and we generate techniques indefinitely. Of course if the object becomes visible this stops the leak.

I'm not sure how to fix this to be honest. As a workaround, we now call material->compile() right after creating the new technique.

I think this should not be too difficult to reproduce but let me know if you need a reproducable example.

paroj commented 3 months ago

could you provide a call stack leading through the shadow render pass towards handleSchemeNotFound?

fbridault commented 3 months ago

Of course, here it is!

sight_viz_scene3d.dll!sight::viz::scene3d::compositor::material_mgr_listener::handleSchemeNotFound(unsigned short __formal, const std::string & _scheme_name, Ogre::Material * _original_material, unsigned short __formal, const Ogre::Renderable * __formal) Line 67 (c:\Dev\sight\libs\viz\scene3d\compositor\material_mgr_listener.cpp:67)
OgreMain_d.dll!Ogre::MaterialManager::_arbitrateMissingTechniqueForActiveScheme(Ogre::Material * mat, unsigned short lodIndex, const Ogre::Renderable * rend) Line 231 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreMaterialManager.cpp:231)
OgreMain_d.dll!Ogre::Material::getBestTechnique(unsigned short lodIndex, const Ogre::Renderable * rend) Line 308 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreMaterial.cpp:308)
OgreMain_d.dll!Ogre::SubEntity::getTechnique() Line 97 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreSubEntity.cpp:97)
OgreMain_d.dll!Ogre::MORecvShadVisitor::visit(Ogre::Renderable * rend, unsigned short lodIndex, bool isDebug, Ogre::Any * pAny) Line 428 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreMovableObject.cpp:428)
OgreMain_d.dll!Ogre::Entity::visitRenderables(Ogre::Renderable::Visitor * visitor, bool debugRenderables) Line 2206 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreEntity.cpp:2206)
OgreMain_d.dll!Ogre::MovableObject::getReceivesShadows() Line 439 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreMovableObject.cpp:439)
OgreMain_d.dll!Ogre::RenderQueue::processVisibleObject(Ogre::MovableObject * mo, Ogre::Camera * cam, bool onlyShadowCasters, Ogre::VisibleObjectsBoundsInfo * visibleBounds) Line 259 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderQueue.cpp:259)
OgreMain_d.dll!Ogre::SceneNode::_findVisibleObjects(Ogre::Camera * cam, Ogre::RenderQueue * queue, Ogre::VisibleObjectsBoundsInfo * visibleBounds, bool includeChildren, bool displayNodes, bool onlyShadowCasters) Line 230 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreSceneNode.cpp:230)
OgreMain_d.dll!Ogre::SceneNode::_findVisibleObjects(Ogre::Camera * cam, Ogre::RenderQueue * queue, Ogre::VisibleObjectsBoundsInfo * visibleBounds, bool includeChildren, bool displayNodes, bool onlyShadowCasters) Line 239 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreSceneNode.cpp:239)
OgreMain_d.dll!Ogre::SceneManager::_findVisibleObjects(Ogre::Camera * cam, Ogre::VisibleObjectsBoundsInfo * visibleBounds, bool onlyShadowCasters) Line 1285 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreSceneManager.cpp:1285)
OgreMain_d.dll!Ogre::SceneManager::_renderScene(Ogre::Camera * camera, Ogre::Viewport * vp, bool includeOverlays) Line 1090 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreSceneManager.cpp:1090)
OgreMain_d.dll!Ogre::Camera::_renderScene(Ogre::Viewport * vp) Line 498 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreCamera.cpp:498)
OgreMain_d.dll!Ogre::Viewport::update() Line 145 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreViewport.cpp:145)
OgreMain_d.dll!Ogre::RenderTarget::_updateViewport(Ogre::Viewport * viewport, bool updateStatistics) Line 196 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:196)
OgreMain_d.dll!Ogre::RenderTarget::_updateAutoUpdatedViewports(bool updateStatistics) Line 176 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:176)
OgreMain_d.dll!Ogre::RenderTarget::updateImpl() Line 153 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:153)
OgreMain_d.dll!Ogre::RenderTarget::update(bool swap) Line 537 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:537)
OgreMain_d.dll!Ogre::CompositorChain::preRenderTargetUpdate(const Ogre::RenderTargetEvent & evt) Line 328 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreCompositorChain.cpp:328)
OgreMain_d.dll!Ogre::RenderTarget::firePreUpdate() Line 360 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:360)
OgreMain_d.dll!Ogre::RenderTarget::_beginUpdate() Line 161 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:161)
OgreMain_d.dll!Ogre::RenderTarget::updateImpl() Line 152 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:152)
OgreMain_d.dll!Ogre::RenderTarget::update(bool swap) Line 537 (c:\Dev\3rdParty\ogre\OgreMain\src\OgreRenderTarget.cpp:537)
sight_module_viz_scene3d_qt.dll!sight::module::viz::scene3d_qt::window::paintGL() Line 776 (c:\Dev\sight\modules\viz\scene3d_qt\window.cpp:776)
...