memory leak on ModifyGeom

Hello,

I have a Dynamic Geometry I want to modify each frame. At start, I create a GeomVertexData with Geom.UHDynamic and I preallocate space by calling setNumRows()

At runtime, I modify this structure at each frame by calling node().modifyGeom().modifyPrimitive().addVertex(). The thing is, at each modification, it seems a copy is made cause I have a leak in memory.

If I increase the size of my geometry on start (by allocating a lots of row), the leak also increase.

If I set the geom-cache-size to 0 in my config.prc, I don’t have this leak anymore.

  1. Am I doing something wrong to modify the geometry ? Cause I thought calling modifyGeom would prevent the geometry from being copied.

  2. Is there a way to disable the cache on this particular object ?

Thanks in advance.

I tried something else.

If I do 5 differents modification on my geometry between 2 frame, I only have the lost for one geometry.

If I do the 5 same modifications, but by doing only one modification at a time between each frame, I have the memory lost for 5 geometries.

This is not a leak. It’s just a cache filling up. Each time a particular object is rendered, if it has to be converted (for instance, to match the color mode to the OpenGL/DirectX backend, or something like that), then it is converted once and stored in the geom-cache.

When you modify the object, you basically create a new object, which then has to be cached again. The old version doesn’t get removed from the cache until the cache fills up.

If you are actually running out of memory, you can reduce the size of this cache to an amount that is a satisfactory balance between memory and performance. You can’t control the caching on a per-object basis; but usually there’s not a reason to.

David

ah, ok the explanation. I thought that by setting Geom.UHDynamic, it would prevent from doing the cache filling.

The thing is, my geometry can be quite big (more than 10Mo) and I made a system to modify it asynchronously.

To describe it simply, when I need to add 100 differents polygon to it, I split it into batch of 25 polygons, and I add a group a each frame in order to not block the rendering. So I can modify my geometry a lot at runtime without having a too big impact on performances (except when there are a lots of modification, it seems it doesn’t like being changed a lot at each frame and the fps decrease).
So if my geometry takes 10Mo in memory, after 4 frames I will have 40Mo in memory. And that’s a simple case, in real I make a lots more changes so I have quickly more than 1GB of ram used.

If I set the geom-cache-size to 15, it seems reasonable for the memory, but I didn’t tested yet the impact on performances. Is it known to be a very good speed optimisation ? If someone already made some speed test, I’ll be glad to see them.

For the caching on a per-object basis, would it be difficult to implement it ? It seems a pretty straightforward operation for me, so I don’t think a lots of code might be impacted by it (but maybe I’m wrong). If you have some information on where in the code I should check in order to implement such a functionality (if it’s reasonable to do such an implementation), it would help me a lot.

Thanks.

Perhaps a better solution would be to pre-munge your Geom, and modify that Geom instead of the original Geom you created. That way, it won’t need to re-copy your Geom every time you modify it, since the pre-munged Geom will be ready to render as-is.

To do this, simply call model.premungeScene() at some point after you have created the model (and after you have opened a graphics window, which creates the necessary graphics context). “model” here is a NodePath at or above your generated GeomNode. Then use the scene graph search operations to find the Geom from the modified scene graph, and do your operations on that Geom.

David

So I tried the premungeScene call and, unfortunately, it didn’t change anything for memory. But it changes something for speed cause now I’m twice faster, which is kind of great.

Just to be sure, here is what I’have done:

geomNode      = GeomNode('selection_manager_triangle')
node          = NodePath(geomNode)
node.setTag("type", "layer_display")
vertex_format = GeomVertexFormat.getV3n3c4()
vertex_buffer = GeomVertexData('hf_vertices', vertex_format, Geom.UHDynamic)
geom          = Geom(vertex_buffer)
geomNode.addGeom(geom)
index_buffer  = GeomTriangles(Geom.UHDynamic)
geom.addPrimitive(index_buffer)
node.reparentTo(root_node)
node.setTransparency(True)
node.setTransparency(TransparencyAttrib.MDual, 1)
node.premungeScene()
new_node = root_node.find('selection_manager_triangle')

and when I want to modify its vertex_data and index_data, I call:

new_node.node().modifyGeom(0).modifyVertexData()
new_node.node().modifyGeom(0).modifyPrimitive(0)

Oh, I think I found the problem.

Instead of calling, new_node.node().modifyGeom(0).modifyVertexData() each time I want to modify my geometry, I need to make this call just after the premungeScene, store the result and use this result for each modification I want to make. It seems to work.

Hmm, modifyVertexData() is designed to return the vertex data itself if there are no outstanding pointers to it, or it will create and return a copy of the vertex data if there are outstanding pointers.

So, it means if you are still hanging on to the vertex data that you got from the last call to modifyVertexData(), it will force a copy when you call it again. So be sure you drop it between calls.

David

Is it a problem to keep modifyGeom around as well? And when you say to drop it, should I force a garbage collect to make sure that the python handle to modifyVertexData is destroyed?