Skip to content

Commit 3d93e9c

Browse files
authored
Destroy material when a mesh is deleted (#324)
* Destroy material when a mesh is deleted Signed-off-by: ahcorde <[email protected]> * Fixed issue Signed-off-by: ahcorde <[email protected]> * make linters happy Signed-off-by: ahcorde <[email protected]> * Improved implementation Signed-off-by: ahcorde <[email protected]> * make linters happy Signed-off-by: ahcorde <[email protected]> * Ogre2 texture destruction some progress Signed-off-by: ahcorde <[email protected]> * Remove meshes when there is no reference Signed-off-by: ahcorde <[email protected]> * cleanup code Signed-off-by: ahcorde <[email protected]> * Avoid breaking ABI Signed-off-by: ahcorde <[email protected]> * make linters happy Signed-off-by: ahcorde <[email protected]> * Fixed tests Signed-off-by: ahcorde <[email protected]> * Fix macos warnings Signed-off-by: ahcorde <[email protected]> * Added feedback Signed-off-by: ahcorde <[email protected]> * Doc fix Signed-off-by: ahcorde <[email protected]>
1 parent ffd8e6d commit 3d93e9c

File tree

13 files changed

+233
-3
lines changed

13 files changed

+233
-3
lines changed

ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh

+8
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ namespace ignition
5656

5757
protected: virtual bool Validate(const MeshDescriptor &_desc);
5858

59+
/// \brief Remove internal material cache for a specific material
60+
/// \param[in] _name Name of the template material to remove.
61+
public: void ClearMaterialsCache(const std::string &_name);
62+
5963
protected: OgreScenePtr scene;
64+
65+
/// \brief Vector with the template materials, we keep the pointer to be
66+
/// able to remove it when nobody is using it.
67+
protected: std::vector<MaterialPtr> materialCache;
6068
};
6169

6270
class IGNITION_RENDERING_OGRE_VISIBLE OgreSubMeshStoreFactory

ogre/include/ignition/rendering/ogre/OgreScene.hh

+4
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ namespace ignition
200200

201201
protected: virtual MaterialMapPtr Materials() const override;
202202

203+
/// \brief Remove internal material cache for a specific material
204+
/// \param[in] _name Name of the template material to remove.
205+
public: void ClearMaterialsCache(const std::string &_name);
206+
203207
private: void CreateContext();
204208

205209
private: void CreateRootVisual();

ogre/src/OgreMaterial.cc

+34-1
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,18 @@ void OgreMaterial::Destroy()
4444
{
4545
if (!this->Scene()->IsInitialized())
4646
return;
47-
47+
std::string materialName;
4848
Ogre::MaterialManager &matManager = Ogre::MaterialManager::getSingleton();
4949
#if OGRE_VERSION_LT_1_10_1
5050
if (!this->ogreMaterial.isNull())
5151
{
52+
materialName = this->ogreMaterial->getName();
53+
54+
this->ogreTexState->setBlank();
55+
auto indexUnitStateToRemove =
56+
this->ogrePass->getTextureUnitStateIndex(this->ogreTexState);
57+
this->ogrePass->removeTextureUnitState(indexUnitStateToRemove);
58+
5259
matManager.remove(this->ogreMaterial->getName());
5360
this->ogreMaterial.setNull();
5461
}
@@ -59,6 +66,32 @@ void OgreMaterial::Destroy()
5966
this->ogreMaterial.reset();
6067
}
6168
#endif
69+
auto &textureManager = Ogre::TextureManager::getSingleton();
70+
auto iend = textureManager.getResourceIterator().end();
71+
for (auto i = textureManager.getResourceIterator().begin(); i != iend;)
72+
{
73+
// A use count of 4 means that only RGM, RM and MeshManager have
74+
// references RGM has one (this one) and RM has 2 (by name and by handle)
75+
// and MeshManager keep another one int the template
76+
Ogre::Resource* res = i->second.get();
77+
if (i->second.useCount() == 4)
78+
{
79+
if (this->textureName == res->getName() &&
80+
res->getName().find(
81+
scene->Name() + "::RenderTexture") == std::string::npos)
82+
{
83+
OgreScenePtr s = std::dynamic_pointer_cast<OgreScene>(this->Scene());
84+
s->ClearMaterialsCache(this->textureName);
85+
this->Scene()->UnregisterMaterial(materialName);
86+
if (i->second.useCount() == 3)
87+
{
88+
textureManager.remove(res->getHandle());
89+
}
90+
break;
91+
}
92+
}
93+
++i;
94+
}
6295
}
6396

6497
//////////////////////////////////////////////////

ogre/src/OgreMesh.cc

+22
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,28 @@ void OgreMesh::Destroy()
5858

5959
auto ogreScene = std::dynamic_pointer_cast<OgreScene>(this->Scene());
6060

61+
std::string ogreMeshName = this->ogreEntity->getMesh()->getName();
62+
6163
ogreScene->OgreSceneManager()->destroyEntity(this->ogreEntity);
6264
this->ogreEntity = nullptr;
65+
66+
auto &meshManager = Ogre::MeshManager::getSingleton();
67+
auto iend = meshManager.getResourceIterator().end();
68+
for (auto i = meshManager.getResourceIterator().begin(); i != iend;)
69+
{
70+
// A use count of 3 means that only RGM and RM have references
71+
// RGM has one (this one) and RM has 2 (by name and by handle)
72+
Ogre::Resource* res = i->second.get();
73+
if (i->second.useCount() == 3)
74+
{
75+
if (res->getName() == ogreMeshName)
76+
{
77+
Ogre::MeshManager::getSingleton().remove(ogreMeshName);
78+
break;
79+
}
80+
}
81+
i++;
82+
}
6383
}
6484

6585
//////////////////////////////////////////////////
@@ -284,6 +304,8 @@ Ogre::SubEntity *OgreSubMesh::OgreSubEntity() const
284304
//////////////////////////////////////////////////
285305
void OgreSubMesh::Destroy()
286306
{
307+
Ogre::MaterialManager::getSingleton().remove(
308+
this->ogreSubEntity->getMaterialName());
287309
OgreRTShaderSystem::Instance()->DetachEntity(this);
288310

289311
BaseSubMesh::Destroy();

ogre/src/OgreMeshFactory.cc

+20
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ bool OgreMeshFactory::IsLoaded(const MeshDescriptor &_desc)
106106
return Ogre::MeshManager::getSingleton().resourceExists(name);
107107
}
108108

109+
//////////////////////////////////////////////////
110+
void OgreMeshFactory::ClearMaterialsCache(const std::string &_name)
111+
{
112+
auto it = this->materialCache.begin();
113+
for (auto &mat : this->materialCache)
114+
{
115+
std::string matName = mat->Name();
116+
std::string textureName = mat->Texture();
117+
if (textureName == _name)
118+
{
119+
this->scene->UnregisterMaterial(matName);
120+
break;
121+
}
122+
++it;
123+
}
124+
if (it != this->materialCache.end())
125+
this->materialCache.erase(it);
126+
}
127+
109128
//////////////////////////////////////////////////
110129
bool OgreMeshFactory::LoadImpl(const MeshDescriptor &_desc)
111130
{
@@ -396,6 +415,7 @@ bool OgreMeshFactory::LoadImpl(const MeshDescriptor &_desc)
396415
if (material)
397416
{
398417
mat->CopyFrom(*material);
418+
materialCache.push_back(mat);
399419
}
400420
else
401421
{

ogre/src/OgreScene.cc

+6
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ VisualStorePtr OgreScene::Visuals() const
345345
return this->visuals;
346346
}
347347

348+
//////////////////////////////////////////////////
349+
void OgreScene::ClearMaterialsCache(const std::string &_name)
350+
{
351+
this->meshFactory->ClearMaterialsCache(_name);
352+
}
353+
348354
//////////////////////////////////////////////////
349355
MaterialMapPtr OgreScene::Materials() const
350356
{

ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh

+13-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace ignition
4141
//
4242
// forward declaration
4343
class Ogre2MeshPrivate;
44+
class Ogre2SubMeshPrivate;
4445

4546
/// \brief Ogre2.x implementation of the mesh class
4647
class IGNITION_RENDERING_OGRE2_VISIBLE Ogre2Mesh :
@@ -118,15 +119,22 @@ namespace ignition
118119
/// \brief Destructor
119120
public: virtual ~Ogre2SubMesh();
120121

122+
// Documentation inherited
123+
public: virtual void Destroy() override;
124+
125+
/// \brief Set the name of the mesh stored in Ogre2
126+
/// \param[in] _name Name of the mesh
127+
public: void SetMeshName(const std::string &_name);
128+
121129
/// \brief Get internal ogre subitem created from this submesh
122130
public: virtual Ogre::SubItem *Ogre2SubItem() const;
123131

124132
/// \brief Helper function for setting the material to use
125133
/// \param[in] _material Material to be assigned to the submesh
126-
protected: virtual void SetMaterialImpl(MaterialPtr _material);
134+
protected: virtual void SetMaterialImpl(MaterialPtr _material) override;
127135

128136
/// \brief Initialize the submesh
129-
protected: virtual void Init();
137+
protected: virtual void Init() override;
130138

131139
/// \brief Ogre subitem representing the submesh
132140
protected: Ogre::SubItem *ogreSubItem = nullptr;
@@ -137,6 +145,9 @@ namespace ignition
137145
/// \brief Make submesh factory our friend so it can create an
138146
/// ogre2 submesh
139147
private: friend class Ogre2SubMeshStoreFactory;
148+
149+
/// \brief Pointer to private data
150+
private: std::unique_ptr<Ogre2SubMeshPrivate> dataPtr;
140151
};
141152
}
142153
}

ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ namespace ignition
9494
/// \brief Pointer to the scene object
9595
protected: Ogre2ScenePtr scene;
9696

97+
/// \brief Remove internal material cache for a specific material
98+
public: void ClearMaterialsCache(const std::string &_name);
99+
97100
/// \brief Pointer to private data class
98101
private: std::unique_ptr<Ogre2MeshFactoryPrivate> dataPtr;
99102
};

ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh

+4
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ namespace ignition
298298
/// \brief Create the vaiours storage objects
299299
private: void CreateStores();
300300

301+
/// \brief Remove internal material cache for a specific material
302+
/// \param[in] _name Name of the template material to remove.
303+
public: void ClearMaterialsCache(const std::string &_name);
304+
301305
/// \brief Create a shared pointer to self
302306
private: Ogre2ScenePtr SharedThis();
303307

ogre2/src/Ogre2Material.cc

+38
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <Hlms/Unlit/OgreHlmsUnlitDatablock.h>
2727
#include <OgreHlmsManager.h>
2828
#include <OgreMaterialManager.h>
29+
#include <OgreTextureManager.h>
2930
#ifdef _MSC_VER
3031
#pragma warning(pop)
3132
#endif
@@ -44,6 +45,9 @@
4445
/// \brief Private data for the Ogre2Material class
4546
class ignition::rendering::Ogre2MaterialPrivate
4647
{
48+
/// \brief Ogre stores the name using hashes. This variable will
49+
/// store the material hash name
50+
public: std::string hashName;
4751
};
4852

4953
using namespace ignition;
@@ -87,6 +91,39 @@ void Ogre2Material::Destroy()
8791
matManager.remove(this->ogreMaterial);
8892
this->ogreMaterial.reset();
8993
}
94+
95+
auto &textureManager = Ogre::TextureManager::getSingleton();
96+
auto iend = textureManager.getResourceIterator().end();
97+
for (auto i = textureManager.getResourceIterator().begin(); i != iend;)
98+
{
99+
// A use count of 4 means that only RGM, RM and MeshManager have references
100+
// RGM has one (this one) and RM has 2 (by name and by handle)
101+
// and MeshManager keep another one int the template
102+
Ogre::Resource* res = i->second.get();
103+
if (i->second.useCount() == 5)
104+
{
105+
if (this->dataPtr->hashName == res->getName() &&
106+
res->getName().find(
107+
scene->Name() + "::RenderTexture") == std::string::npos)
108+
{
109+
Ogre2ScenePtr s = std::dynamic_pointer_cast<Ogre2Scene>(this->Scene());
110+
s->ClearMaterialsCache(this->textureName);
111+
this->Scene()->UnregisterMaterial(this->name);
112+
if (i->second.useCount() == 4)
113+
{
114+
textureManager.remove(res->getHandle());
115+
if (!this->textureName.empty())
116+
{
117+
Ogre::HlmsTextureManager *hlmsTextureManager =
118+
this->ogreHlmsPbs->getHlmsManager()->getTextureManager();
119+
hlmsTextureManager->destroyTexture(this->textureName);
120+
}
121+
}
122+
break;
123+
}
124+
}
125+
++i;
126+
}
90127
}
91128

92129
//////////////////////////////////////////////////
@@ -538,6 +575,7 @@ void Ogre2Material::SetTextureMapImpl(const std::string &_texture,
538575
Ogre::HlmsTextureManager::TextureLocation texLocation =
539576
hlmsTextureManager->createOrRetrieveTexture(baseName,
540577
this->ogreDatablock->suggestMapTypeBasedOnTextureType(_type));
578+
this->dataPtr->hashName = texLocation.texture->getName();
541579

542580
Ogre::HlmsSamplerblock samplerBlockRef;
543581
samplerBlockRef.mU = Ogre::TAM_WRAP;

ogre2/src/Ogre2Mesh.cc

+46
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include <Hlms/Pbs/OgreHlmsPbsDatablock.h>
2525
#include <OgreItem.h>
2626
#include <OgreSceneManager.h>
27+
#include <OgreMeshManager.h>
28+
#include <OgreMeshManager2.h>
29+
#include <OgreMaterialManager.h>
2730
#ifdef _MSC_VER
2831
#pragma warning(pop)
2932
#endif
@@ -40,6 +43,14 @@ class ignition::rendering::Ogre2MeshPrivate
4043
{
4144
};
4245

46+
/// brief Private implementation of the Ogre2SubMesh class
47+
class ignition::rendering::Ogre2SubMeshPrivate
48+
{
49+
/// \brief name of the mesh inside the mesh manager to be able to
50+
/// remove it
51+
public: std::string subMeshName;
52+
};
53+
4354
using namespace ignition;
4455
using namespace rendering;
4556

@@ -271,6 +282,7 @@ SubMeshStorePtr Ogre2Mesh::SubMeshes() const
271282

272283
//////////////////////////////////////////////////
273284
Ogre2SubMesh::Ogre2SubMesh()
285+
: dataPtr(new Ogre2SubMeshPrivate)
274286
{
275287
}
276288

@@ -280,6 +292,40 @@ Ogre2SubMesh::~Ogre2SubMesh()
280292
this->Destroy();
281293
}
282294

295+
//////////////////////////////////////////////////
296+
void Ogre2SubMesh::SetMeshName(const std::string &_name)
297+
{
298+
this->dataPtr->subMeshName = _name;
299+
}
300+
301+
//////////////////////////////////////////////////
302+
void Ogre2SubMesh::Destroy()
303+
{
304+
auto meshManager = Ogre::MeshManager::getSingletonPtr();
305+
if (meshManager)
306+
{
307+
auto iend = meshManager->getResourceIterator().end();
308+
for (auto i = meshManager->getResourceIterator().begin(); i != iend;)
309+
{
310+
// A use count of 3 means that only RGM and RM have
311+
// references RGM has one (this one) and RM has 2 (by name and by handle)
312+
Ogre::Resource* res = i->second.get();
313+
if (i->second.useCount() == 3)
314+
{
315+
if (res->getName() == this->dataPtr->subMeshName)
316+
{
317+
Ogre::v1::MeshManager::getSingleton().remove(
318+
this->dataPtr->subMeshName);
319+
Ogre::MeshManager::getSingleton().remove(this->dataPtr->subMeshName);
320+
break;
321+
}
322+
}
323+
++i;
324+
}
325+
}
326+
BaseSubMesh::Destroy();
327+
}
328+
283329
//////////////////////////////////////////////////
284330
Ogre::SubItem *Ogre2SubMesh::Ogre2SubItem() const
285331
{

0 commit comments

Comments
 (0)