Unload GeometryGroup and load a new GeometryGroup in runtime

Hello.

I am trying to build a 3D Models Viewer. This viewer has two buttons: “Previous model” and “Next model” . When the user press one of them, the software change the current model by a new one.

Every model is loaded into an array when the software is initialized.

My problem is that when a new model is changed, the GPU memory usage increase. After many changes, the software crash(out of memory). But if I push “Back model” button, the software changes the model but GPU memory usage does not increase.

This is my condensed code:

GeometryGroup models[10]; // I want to show 10 models
int current_mainmodel_index = 0;

void PathTracerScene::createGeometry(){
        Group maingroup = m_context->createGroup();
        [...] // Here load 10 OBJ into models[10]

        maingroup->addChild(models[current_mainmodel_index]); // Add the first model to the maingroup
        maingroup->setAcceleration(m_context->createAcceleration("Sbvh","Bvh"));
        m_context["top_object"]->set(maingroup);
}

// When I push "Next" or "Back" button, I call this method;
void PathTracerScene::changeMainObject(unsigned int index){	
	Group maingroup = m_context["top_object"]->getGroup();
	maingroup->setChild(0, models[index]);
	m_context["top_object"]->set(maingroup);
}

How can I change to properly the current GeometryGroup by the new one?

Specs:

Windows 10 Pro 64-bit
Intel Core i7 4790K @ 4.00GHz
NVIDIA GeForce GTX TITAN X
RAM 32,0GB

Optix 3.9
Nvidia controller: 364.72

In principle this should work. You’re building multiple GeometryGroups and assign only one of them to the scene at a time. The amount of GPU memory used for the accelerations structures should only contain the active objects. Could be that there is some caching going on.

In any case, when exchanging the GeometryGroup under a Group node you should mark the Group’s accelerations structure dirty.
It’s also not necessary to set the top_object again. It hasn’t changed.

Also mind that the C++ wrapper classes are not building a ref-counted shadow graph and do not destroy OptiX objects automatically. You’re responsible to track all OptiX objects in your scene and call destroy manually where needed before deleting the C++ wrapper objects.

I would recommend to use class member variables to do that. You should be able to identify the root Group and its Acceleration directly. That would avoid the m_context[“top_object”]->getGroup(); call as well

From the code it’s not quite clear what the different GeometryGroups are. You’re using main_objects[current_mainmodel_index].getGeometryGroup() and models[index]. I guessed how it’s mapping in the code below.

Something like this:

void PathTracerScene::createGeometry()
{
  // Here load 10 OBJ into m_models[10]

  m_maingroup = m_context->createGroup();
  m_maingroup->addChild(m_models[current_mainmodel_index]);
  m_maingroupAcceleration = m_context->createAcceleration("Sbvh","Bvh"); // Remember the Acceleration to be able to call markDirty().
  // Sbvh is the slowest builder, try Bvh and Trbvh builders as well if exchanging models takes too long 
  m_maingroup->setAcceleration(m_maingroupAcceleration);
  m_context["top_object"]->set(m_maingroup);
}

void PathTracerScene::changeMainObject(unsigned int index)
{
  m_maingroup->setChild(0, m_models[index]);
  m_maingroupAcceleration->markDirty(); // Geometry under root Group changed, must rebuild AS.
  // m_context["top_object"]->set(m_maingroup); // Redundant!
}

If the models are too big to be present in the scene at the same time, none of the other possible methods to switch between models faster would apply.

When reporting OptiX issues, please always list the following system information:
OS version, installed GPU(s), display driver version, OptiX version, CUDA toolkit version you used to compile the PTX code.

Sorry but if I erase this line:

m_context["top_object"]->set(m_maingroup)

, the new model is not shown and the scene remains empty.

Though I delete manually the GeometryGroups, the memory usage GPU not decrease. I delete the GeometryGroups with
this line:

m_models[index].getGeometryGroup()->destroy();

Perhaps the software is deleting the models from the Host memory?

Thanks for your help!

If you call PathTracerScene::createGeometry() once and before PathTracerScene::changeMainObject() and never change the top_object anywhere else in the code, I see no reason to set this ever again. If you change the scene beneath that node you must dirty the acceleration structure.

Other things to try would be to use different accelelation builders for the root node including NoAccel which should rule out acceleration structure update issues.
Try to enable all OptiX exceptions during debugging to see if anything else fires.

The destroy() deletes all OptiX data assigned to that GeometryGroup. It’s gone then and can’t be used anymore.

How do you measure the GPU memory usage?

Code excerpts don’t help to further analyze the issue.
If you’re able to provide a minimal reproducer which shows the problem, that would be helpful.
Have a look into next youngest thread where I explained how to do an OptiX API Capture (OAC) trace.
https://devtalk.nvidia.com/default/topic/935054/optix/time-varying-rendering-with-optix/
This question there is actually similar to yours.

I try all acceleration builds for the root node (m_maingroup), but the model is not yet displayed. And if I use “NoAccel” or “Lbvh”, the program crash with this error:

OptiX Error: Unknown error (Details: function "_rtContextLaunch2D" caught exception: Encountered a CUDA error: driver().cuModuleGetTexRef(&m_texRef, module, name) returned (500): Not found, [7798809]

Is there some way to delete the GeometryGroup and to release the occupied memory the GPU?

I use MSI Afterburner to measure the GPU memory.

Perfect, I try to use OptiX API Capture (OAC).

>>Is there some way to delete the GeometryGroup and to release the occupied memory the GPU?<<

The GPU memory for destroyed objects should be released during the next launch which rebuilds the acceleration structures.

There is not enough information about what you’re doing to figure out what the problem with the launch error is.

For the very first scene setup I normally call these three OptiX context functions to figure out what takes how long and if there are errors before the first launch.
For debugging purposes only (this affects performance!) you could add these before the first launch you do after you changed the scene hierarchy to isolate where the error might be.

m_context->compile();       // Trigger possible recompile of the kernel when exchanging scene data. 
m_context->validate();      // Check the integrity of the scene and variables.
m_context->launch(0, 0, 0); // Dummy 2D launch to rebuild acceleration structures.

Search for these on the forum to find more example code from me.