(viz): implement a resource sharing mecanism
Description
Adaptor inputs (except STransform
) are always copied to new ogre resources. This is really resource-intensive, especially when rendering to multiple scenes or layers.
Because of this we currently rely on a hack to avoid copying resources when the scene's qt container is not displayed.
We need to find a way to share large meshes or 3D images between adaptors.
Proposal
- Implement resource sharing across all adaptors.
- Use the object's UID to find/create a shared resource.
- Make sharing optional, perhaps by adding a configuration parameter (e.g. 'sharing' or 'forceCopy')
Functional specifications
We use Ogre textures for the following adaptors:
SNegato2D
SNegato3D
-
SVolumeRender
(actually done inIVolumeRenderer
)
We use Ogre mesh resources for the following adaptors:
SMesh
SPointList
Indeed we would like to share resources between them. I think we should think the other way. Most of the time, we want them to be shared. In rare cases, we might want to get another instance of the resource, that could be shared as well.
To this end, I propose to add a configuration parameter instance
similar as the transform
parameter of the STransform
adaptor :
<!-- Use the default shared copy of "image" -->
<service uid="adaptor1" type="sight::module::viz::scene3d::adaptor::SNegato2D">
<inout key="image" uid="image" />
<inout key="tf" uid="..." />
<config layer="default" />
</service>
<!-- Use a named shared copy "instance1" of "image" -->
<service uid="adaptor2" type="sight::module::viz::scene3d::adaptor::SNegato2D">
<inout key="image" uid="image" />
<inout key="tf" uid="..." />
<config layer="default" instance="instance1" />
</service>
<!-- Use the named shared copy "instance1" of "image" -->
<service uid="adaptor3" type="sight::module::viz::scene3d::adaptor::SNegato2D">
<inout key="image" uid="image" />
<inout key="tf" uid="..." />
<config layer="default" instance="instance1" />
</service>
<!-- Use the default shared copy of "image" -->
<service uid="adaptor4" type="sight::module::viz::scene3d::adaptor::SNegato2D">
<inout key="image" uid="image" />
<inout key="tf" uid="..." />
<config layer="default" />
</service>
<!-- Report an error in this case ? "instance1" is an instance of "image", not "image2" -->
<service uid="adaptor5" type="sight::module::viz::scene3d::adaptor::SNegato2D">
<inout key="image" uid="image2" />
<inout key="tf" uid="..." />
<config layer="default" instance="instance1" />
</service>
By default, the instance name would be the id of the object.
With this mechanism, we would also be able to share resources between XML configurations. If we use a specific instance name, we can pass the instance name as a configuration parameter.
Technical specifications
Basically, we need a generic resource manager:
class ResourceManager
{
/// Add a reference to a resource. If it does not exist, it creates a new one, otherwise
/// this returns the existing one.
/// @return shared pointer on the resource
Resource::sptr instantiate(std::string, sight::data::Object::wptr);
/// Remove a reference to a resource. If this was the last reference, it destroys it.
void release(Resource::sptr);
struct Resource
{
Ogre::Resource resource;
sight::data::Object::wptr object;
};
std::map<std::string, Resource::sptr > m_registry;
}
Using shared_ptr
, we can easily track down the number of users of a resource and delete it in remove_resource() when no one no longer uses it.
Test plan
- The ResourceManager should be unit tested.
- Existing applications like SightViewer should be tested. A GPU memory consumption comparison should show the benefit of the approach.