I've recently modified my project to statically link Ogre, and with this task I statically linked the plugins we use and handled their initialization and destruction. After making these changes we noticed that we were getting segfaults when shutting down Ogre(which in this case is also when we close our app). Long story short the issue turned out to be that we were cleaning up the rendersystem plugins too early.
We have our engine setup such that the actual render specific stuff (such as rendersystems) are initialized with our GraphicsManager. Ogre::Root however is initialized with our own root object, as Ogre is currently being used for more than just rendering. So when our graphics system was shutdown we removed the hardware buffers that were tied to it, but not all objects that actually use them are freed by this point. We were diligent about cleaning up our resources (we really shouldn't have to be in this specific case), but what got us anyway were the Prefab meshes. During the Ogre::Root destruction the Prefab_Plane was being removed from the ResourceGroupManager and getting destroyed. When the "sharedVertexData" was being deleted and it attempted to get the HardwareBufferManager and clean up the buffers which led to the segfault I was experiencing.
I suppose to avoid this kind of thing I could ensure all the dangling shared pointers on my end are cleaned up, and I could manually remove from their managers (and resource groups) all resources that use hardware buffers before destroying the rendersystems. However it seems very odd to me that the current way the Ogre shutdown sequence works, it expects the user to just let Ogre handle it. So if for example someone wanted to shutdown the rendersystem and initialize a new one without re-creating Ogre::Root they can't do it cleanly.
I'm not entirely sure what all can be done to address this. One idea that came to mind is moving the initialization and shutdown of the MeshManager to the base Rendersystem class, although I don't know what the full implications of this would be. But I feel Ogre could benefit from this cleanup of it's shutdown sequence.
Rendersystem Shutdown
-
- Ogre Magi
- Posts: 1137
- Joined: Mon May 07, 2007 3:43 am
- Location: Ossining, New York
- x 13
Re: Rendersystem Shutdown
Sounds like you are using the API wrongly to me 

-
- Greenskin
- Posts: 125
- Joined: Mon Feb 22, 2010 7:48 pm
- x 9
Re: Rendersystem Shutdown
Using it differently, maybe. But when static linking the rendersystems (which is the recommended way to do it in the wiki when you statically link OgreMain) you have to oversee the initialization of the plugin yourself. Yet Ogre::Root wants to oversee the destruction. To me this is like new'ing something and being told "don't worry about the delete". That's just bad coding in C++. I'd like the same thing I used to initialize the rendersystems to be allowed to de-initialize them as well, independant of Ogre::Root.
Admittedly this is something that is lower priority, as very few others are having the same issue (currently). But if the fix can be as simple as creating and destroying the MeshManager in the base rendersystem class instead of Ogre::Root, why not?
Edit: I realized after posting that you may have been referring to my comment where you could clear out all the resources that use hardware buffers and get away with shutting down the rendersystem early. If you feel that I should opt for that rather than trying to alter Ogre, I disagree. But if Ogre wants to go that way documentation clarifying that should be added. That bit of info was not obvious to me despite looking at the doc's. In fact the exact wording in the doc's for the method "RenderSystem::shutdown()" is "Shutdown the renderer and cleanup resources." It absolutely is not cleaning up all the resources.
Admittedly this is something that is lower priority, as very few others are having the same issue (currently). But if the fix can be as simple as creating and destroying the MeshManager in the base rendersystem class instead of Ogre::Root, why not?
Edit: I realized after posting that you may have been referring to my comment where you could clear out all the resources that use hardware buffers and get away with shutting down the rendersystem early. If you feel that I should opt for that rather than trying to alter Ogre, I disagree. But if Ogre wants to go that way documentation clarifying that should be added. That bit of info was not obvious to me despite looking at the doc's. In fact the exact wording in the doc's for the method "RenderSystem::shutdown()" is "Shutdown the renderer and cleanup resources." It absolutely is not cleaning up all the resources.
-
- OGRE Expert User
- Posts: 1920
- Joined: Sun Feb 19, 2012 9:24 pm
- Location: Russia
- x 201
Re: Rendersystem Shutdown
You have an awkward situation but partially because you're trying to use the rendering engine not only for rendering per se. Moving control of MeshManager to RenderSystem is not a very good idea because a) it breaks the current ownership/control logic currently employed for various managers; b) it couples different abstractions in a way that is not logically sound but rather because that will fix your particular issue.
I'd recommend doing this before destroying the render system:
That should dispose the prefabs and avoid the issue with accessing invalidated hardware buffers. It's an awkward solution but such is your way of using Ogre.
I'd recommend doing this before destroying the render system:
Code: Select all
ResourceGroupManager::getSingleton().clearResourceGroup( ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME );
-
- Greenskin
- Posts: 125
- Joined: Mon Feb 22, 2010 7:48 pm
- x 9
Re: Rendersystem Shutdown
Thanks for your input, bstone. Could you go into a little more detail regarding your points?
Regarding control logic, if you mean how it's accessed in the API, virtually all calls to it are made through singleton access. They don't make calls on root to get at it. Even Ogre::Root doesn't access the MeshManager through the pointer that is right there, instead opting for singleton access (in Root::oneTimePostWindowInit()). Moving it wouldn't even change the timing of when you could access it since nothing in Ogre will attempt to create a mesh before Root and the Rendersystem are initialized as is. It would still get initialized at approximately the same time.
I don't really understand your second point as clearly as I would like. I agree your line that you provided would address my issue, as would calling "removeAll()" on the MeshManager or a number of other permutations of something similar. However using that seems like a bandaid fix at current.
Regarding control logic, if you mean how it's accessed in the API, virtually all calls to it are made through singleton access. They don't make calls on root to get at it. Even Ogre::Root doesn't access the MeshManager through the pointer that is right there, instead opting for singleton access (in Root::oneTimePostWindowInit()). Moving it wouldn't even change the timing of when you could access it since nothing in Ogre will attempt to create a mesh before Root and the Rendersystem are initialized as is. It would still get initialized at approximately the same time.
I don't really understand your second point as clearly as I would like. I agree your line that you provided would address my issue, as would calling "removeAll()" on the MeshManager or a number of other permutations of something similar. However using that seems like a bandaid fix at current.
-
- OGRE Expert User
- Posts: 1920
- Joined: Sun Feb 19, 2012 9:24 pm
- Location: Russia
- x 201
Re: Rendersystem Shutdown
The first point was about ownership not access. The beauty of singletons is exactly why you can move the ownership of MeshManager around without changing a single line of code that accesses it in Ogre. But that alone doesn't justify moving MeshManager's ownership to RenderSystem (well, beyond fixing flaws in your initialization/deinitialization sequence). It's much better to keep the ownership uniform across all "manager" classes (which it is now) because it's easier to control their life-time that way and is easier to maintain in general.
About the second point. The abstractions of MeshManager and RenderSystem are loosely related and it's better to keep them that way. Consider this: you can use MeshManager without a render system at all and that is extremely important in a few use-cases that can't be discarded (OgreXMLConverter is one example). You can use a RenderSystem without MeshManager as well which might seem less important but it's a good way to have it. If we moved ownership of MeshManager to RenderSystem we would lose that flexibility at once.
Now if you'd be interested in hearing my view of a proper solution then I'd let MeshManager subscribe to a notification about the vertex/index buffers being invalidated. That would let MeshManager clean up the problematic resources before it's too late. HardwareBufferManager would be a good place to provide the notification from. This way you wouldn't introduce any excessive coupling between unrelated abstractions.
About the second point. The abstractions of MeshManager and RenderSystem are loosely related and it's better to keep them that way. Consider this: you can use MeshManager without a render system at all and that is extremely important in a few use-cases that can't be discarded (OgreXMLConverter is one example). You can use a RenderSystem without MeshManager as well which might seem less important but it's a good way to have it. If we moved ownership of MeshManager to RenderSystem we would lose that flexibility at once.
Now if you'd be interested in hearing my view of a proper solution then I'd let MeshManager subscribe to a notification about the vertex/index buffers being invalidated. That would let MeshManager clean up the problematic resources before it's too late. HardwareBufferManager would be a good place to provide the notification from. This way you wouldn't introduce any excessive coupling between unrelated abstractions.
-
- Ogre Magi
- Posts: 1137
- Joined: Mon May 07, 2007 3:43 am
- Location: Ossining, New York
- x 13
Re: Rendersystem Shutdown
Here's how I shut down in a statically linked environment: (see gfx_init and gfx_shutdown) http://gritengine.svn.sourceforge.net/v ... iew=markup
I don't try and destroy the render system object before I destroy Root though, I'm not sure why you'd want to do that.
The way I see it, the render system is tied up so closely with the whole of ogre, it makes no sense to have Ogre::Root without a rendersystem available to it. The only reason they are initialised separately is to allow you to create a rendersystem of your choice and give it to Ogre::Root, which must be done immediately upon creating it and then becomes a part of that Root object. It is asymmetric I agree, but an alternative API (where you didn't do 'new') would be more complex.
I don't try and destroy the render system object before I destroy Root though, I'm not sure why you'd want to do that.
The way I see it, the render system is tied up so closely with the whole of ogre, it makes no sense to have Ogre::Root without a rendersystem available to it. The only reason they are initialised separately is to allow you to create a rendersystem of your choice and give it to Ogre::Root, which must be done immediately upon creating it and then becomes a part of that Root object. It is asymmetric I agree, but an alternative API (where you didn't do 'new') would be more complex.
-
- Greenskin
- Posts: 125
- Joined: Mon Feb 22, 2010 7:48 pm
- x 9
Re: Rendersystem Shutdown
@bstone
That is much clearer. Thanks. There are a couple flaws in your logic though. Not all managers are owned by Ogre::Root. While a vast majority of them are, HardwareBufferManager and TextureManager are owned by the rendersystem at current. While I understand both managers are probably there more because they have to be rather than making the code logically flow, it does make a degree of sense to share the manager lifetime with other managers it depends on. In this case the MeshManager does absolutely require a HardwareBufferManager to be present for it to operate properly. It really wouldn't get more difficult to maintain, but it would be safer to maintain since the lifetime a manager would have to have is enforced better (again, MeshManager needing HardwareBufferManager) plus that design communicates the demands of the system better.
I agree having them be separable is a good feature, and I wouldn't dare push for a fix that would break the XML Converter. So I took a quick look at the XML Converter code since it seemed odd that it would be able to provide buffers without a rendersystem. Ogre::Root nor any rendersystem is initialized in the tool, instead each manager and serializer is initialized manually that it needs to do it's job. The HardwareBufferManager it gets is just the DefaultHardwareBufferManager, which I am guessing is just a dummy system that makes buffers in system memory only. So making that change wouldn't actually break the XML Converter. In fact it appears no code would need to changed at all in it. How the XML Converter does it is pretty much how anyone that wants to do it would have to, because of the dependency between the MeshManager and the HardwareBufferManager. There is no situation where it's safe to create Ogre::Root, skip making a rendersystem, and with no additional code have it be safe to create a mesh. Manually new'ing managers would be a requirement as it's always been. Only change would be for people that made Ogre::Root but skipped the rendersystem would need 1 more line of code. Those that skipped Ogre::Root entirely wouldn't have to change a thing.
The example of using a rendersystem without a MeshManager seems even more corner case than my issue. There is a case to be made for 2D graphics, but if someone wants only 2D graphics in a liberally licensed engine, they'll go to SDL. Not Ogre. Even if someone did decide Ogre was better suited for their needs, they could just not use the MeshManager. It would take up some memory, sure, but wouldn't cause any other issues.
Your solution would absolutely work, and if that's the way the Ogre Team wants to do it I would gladly accept it. But it doesn't seem proper to me, primarily because they aren't as unrelated as you mentioned. As I stated in my post above, at a minimum I'd like to see documentation is amended. As long as people are less likely to encounter the same issue I did I'm happy.
@sparkprime
I stated before I want destroy the rendersystem before Root because they are initialized by different objects in my engine. The design works quite well for us aside from this one hiccup which I see as bad coding practice on Ogre's part. The rendersystem is a critical class, absolutely. But as bstone mentioned there are use cases for Ogres facilities without one. Also the idea that it is forbidden to shutdown a plugin before Root is...well it's just bad. If Ogre really wants it to be that tightly coupled it should probably be a component instead of a plugin and Root should have complete control over it's lifetime.
That is much clearer. Thanks. There are a couple flaws in your logic though. Not all managers are owned by Ogre::Root. While a vast majority of them are, HardwareBufferManager and TextureManager are owned by the rendersystem at current. While I understand both managers are probably there more because they have to be rather than making the code logically flow, it does make a degree of sense to share the manager lifetime with other managers it depends on. In this case the MeshManager does absolutely require a HardwareBufferManager to be present for it to operate properly. It really wouldn't get more difficult to maintain, but it would be safer to maintain since the lifetime a manager would have to have is enforced better (again, MeshManager needing HardwareBufferManager) plus that design communicates the demands of the system better.
I agree having them be separable is a good feature, and I wouldn't dare push for a fix that would break the XML Converter. So I took a quick look at the XML Converter code since it seemed odd that it would be able to provide buffers without a rendersystem. Ogre::Root nor any rendersystem is initialized in the tool, instead each manager and serializer is initialized manually that it needs to do it's job. The HardwareBufferManager it gets is just the DefaultHardwareBufferManager, which I am guessing is just a dummy system that makes buffers in system memory only. So making that change wouldn't actually break the XML Converter. In fact it appears no code would need to changed at all in it. How the XML Converter does it is pretty much how anyone that wants to do it would have to, because of the dependency between the MeshManager and the HardwareBufferManager. There is no situation where it's safe to create Ogre::Root, skip making a rendersystem, and with no additional code have it be safe to create a mesh. Manually new'ing managers would be a requirement as it's always been. Only change would be for people that made Ogre::Root but skipped the rendersystem would need 1 more line of code. Those that skipped Ogre::Root entirely wouldn't have to change a thing.
The example of using a rendersystem without a MeshManager seems even more corner case than my issue. There is a case to be made for 2D graphics, but if someone wants only 2D graphics in a liberally licensed engine, they'll go to SDL. Not Ogre. Even if someone did decide Ogre was better suited for their needs, they could just not use the MeshManager. It would take up some memory, sure, but wouldn't cause any other issues.
Your solution would absolutely work, and if that's the way the Ogre Team wants to do it I would gladly accept it. But it doesn't seem proper to me, primarily because they aren't as unrelated as you mentioned. As I stated in my post above, at a minimum I'd like to see documentation is amended. As long as people are less likely to encounter the same issue I did I'm happy.
@sparkprime
I stated before I want destroy the rendersystem before Root because they are initialized by different objects in my engine. The design works quite well for us aside from this one hiccup which I see as bad coding practice on Ogre's part. The rendersystem is a critical class, absolutely. But as bstone mentioned there are use cases for Ogres facilities without one. Also the idea that it is forbidden to shutdown a plugin before Root is...well it's just bad. If Ogre really wants it to be that tightly coupled it should probably be a component instead of a plugin and Root should have complete control over it's lifetime.
-
- Ogre Magi
- Posts: 1137
- Joined: Mon May 07, 2007 3:43 am
- Location: Ossining, New York
- x 13
Re: Rendersystem Shutdown
So what do you do with the Root object after destroying the render system?Mako_energy wrote:I stated before I want destroy the rendersystem before Root because they are initialized by different objects in my engine.
I do agree that Ogre is not very compartmentalised, for example not using Root is currently impossible due to some easily avoidable design flaws, even if one uses *only* the RenderSystem and nothing else. I find the design of OgreXMLConverter very hacky too.
But I don't see any motivation for the cases that cause a problem here.
-
- Greenskin
- Posts: 125
- Joined: Mon Feb 22, 2010 7:48 pm
- x 9
Re: Rendersystem Shutdown
In most cases, after our GraphicsManager object is destroyed (which is responsible for the rendersystems) our Root object is also destroyed shortly after. However that isn't enforced strictly, and that is the way we want to keep it so the system is as flexible as possible.sparkprime wrote:So what do you do with the Root object after destroying the render system?
If your question is more to the effect of what I do outside of rendering with Ogre, than the answer would be: "primarily the loading of resources." This is something I do want to change in the long term, but it's not critical and there is a ton of interest in moving it to a component from others in the community. Also considering how tightly coupled it is with Ogremain right now I'm not exactly sure how the API will change as well as the expectations that will be incurred after such a change if it occurs. So I'm not in a rush to work around the hulk of a system it is just to do it all over again.
TLDR: I shake my fist at the resource system.