Crash when unloading a mesh that has a single big vertex buffer shared by index buffers in multiple submeshes

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
tlogre
Gnoblar
Posts: 18
Joined: Tue Oct 03, 2017 7:27 pm
x 1

Crash when unloading a mesh that has a single big vertex buffer shared by index buffers in multiple submeshes

Post by tlogre »

I have a crash when unloading a mesh that includes multiple submeshes.
I have narrowed down the general cause of the problem:
  • The multiple submeshes of my mesh all share a common vertex buffer and the deletion logic is attempting to destroy the same vertex buffer more than once (which ends badly)
    In my app, I need to create the mesh and its submeshes on the fly because the vertices and materials change based on data that is created within my app.
Unfortunately, due to this problem, I am unable to unload a mesh that contains multiple submeshes that share a single set of vertices. My code will always crash due to an attempt to unload the mesh because the vertex buffer will be deleted more than once. The approach described below does render correctly, the problem only arises when I attempt to unload the mesh.

I would welcome any advice regarding how I can share a single set of vertices between submeshes. Below is a description of how the crash occurs.

At the end of this post is code showing how I allocate my submeshes.

The crash occurs as follows


In my code, I call unload to delete the mesh.

Code: Select all

pMyMesh->unload();
This leads to a call to Resource::unload()..
Which leads to a call to Mesh::unloadImpl()
Mesh::unloadImpl has a loop to delete my submeshes

Code: Select all

    void Mesh::unloadImpl()
    {
        // Teardown submeshes
..
        while( itor != end )
            OGRE_DELETE *itor++;

The destructor for SubMesh calls destroyVaos

Code: Select all

    //-----------------------------------------------------------------------
    SubMesh::~SubMesh()
    {
        destroyShadowMappingVaos();
        destroyVaos( mVao[VpNormal], mParent->mVaoManager );
    }
The SubMesh::destroyVaos has a loop that deletes the vertex and index buffers
I stepped through the loop and it appears to work fine for the first submesh. Both the vertex buffer and the index buffer for the first submesh are deleted.

Code: Select all

    void SubMesh::destroyVaos( VertexArrayObjectArray &vaos, VaoManager *vaoManager,
                               bool destroyIndexBuffer )
    {



But, on return from the first call to destroyVaos, the next call to OGRE_DELETE *itor++; in the mesh destructor leads to a second call to destroyVaos which leads to second call to destroy the same vertex buffer. The vertex buffer has already been deleted, which leads to a crash. The SubMesh:destroyVaos logic has a vector to keep track of buffers that have already been deleted within that submesh. But, in my case, I have a mesh that contains multiple submeshes which share a vertex buffer, so this logic does not kick in.




Below is a description of how I allocate the mesh


My mesh uses a single big set of vertices in a vertex buffer, which I create with the following calls:

Code: Select all

	//	Create a single big list of vertices that will be shared by all submeshes
	MeshVertexWithColor *cubeVertices = reinterpret_cast<MeshVertexWithColor*>(OGRE_MALLOC_SIMD(
		sizeof(MeshVertexWithColor) * NumVerticies,
		Ogre::MEMCATEGORY_GEOMETRY));
..	code to copy vertex values into cubeVertices
		//Create the actual vertex buffer.
		vertexBuffer = vaoManager->createVertexBuffer(vertexElements, NumVerticies,
			partialMesh ? Ogre::BT_DEFAULT :
			Ogre::BT_IMMUTABLE,
			cubeVertices, false);
After creating that big vertex buffer, I create about five submeshes that utilize those same vertices. Each submesh has its own material. This code is based on the “dynamic geometry” sample app, but I welcome finding out that I missed something that is leading to the problem.

Code: Select all

	Ogre::SubMesh *subMesh;
	subMesh = pTheMesh->createSubMesh();
	//Now the Vao
	Ogre::VertexBufferPackedVec vertexBuffers;
	vertexBuffers.push_back(vertexBuffer);
	Ogre::IndexBufferPacked *indexBuffer = createIndexBuffer(*SubMeshIndexList); //Create the actual index buffer
	Ogre::VertexArrayObject *vao = vaoManager->createVertexArrayObject(
		vertexBuffers, indexBuffer, Ogre::OT_TRIANGLE_LIST);

	//Each Vao pushed to the vector refers to an LOD level.
	//Must be in sync with mesh->mLodValues & mesh->mNumLods if you use more than one level
	subMesh->mVao[Ogre::VpNormal].push_back(vao);
	//Use the same geometry for shadow casting.
	subMesh->mVao[Ogre::VpShadow].push_back(vao);
	subMesh->setMaterialName(MaterialNa
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Crash when unloading a mesh that has a single big vertex buffer shared by index buffers in multiple submeshes

Post by dark_sylinc »

See this post: viewtopic.php?t=92957#p539422
- Does V2 support shared vertex buffers within a mesh?
- It does but it's not encouraged. This means that if you force vertex buffer sharing, on destruction Ogre will try to delete the same buffer twice, hence you need to delete the buffer yourself and unset it from the submeshes before shutdown to prevent Ogre from crashing.

Other utility functions like the ones in VertexShadowMapHelper might not behave correctly if buffers are shared.

If you manage the buffers yourself, rendering-wise it will work.
Cheers
tlogre
Gnoblar
Posts: 18
Joined: Tue Oct 03, 2017 7:27 pm
x 1

Re: Crash when unloading a mesh that has a single big vertex buffer shared by index buffers in multiple submeshes

Post by tlogre »

Thank you
tlogre
Gnoblar
Posts: 18
Joined: Tue Oct 03, 2017 7:27 pm
x 1

Re: Crash when unloading a mesh that has a single big vertex buffer shared by index buffers in multiple submeshes

Post by tlogre »

Thank you again for your response.

Based on your advice, I was able to get the vertex and index buffers deleted.

The basic steps I used:

  • I created a single vertex buffer and held onto to my own pointer to same.
  • I created submeshes using the approach shown earlier in this thread
When the time comes to delete...
  • I loop through the submeshes in my Ogre::Mesh
  • For each VertexArrayObject, I get the vertexBuffers array and just call clear()
  • I don't do anything to the index buffers
  • I call unload() on my mesh which then loops through and destroys the index buffers (but not the vertex buffer)
  • I then call destroyVertexBuffer on my own pointer to a single shared vertex buffer
Post Reply