DX11 closing assert: "Not all resources have been released!"

Problems building or running the engine, queries about how to use features etc.
User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

Ogre Version: 13.6.5
Operating System: windows
Render System: DX11

Hi,
I ported the SHMUP Creator engine to DX11 and it works. As a bonus, all games made with this engine are now working on SteamDeck, thanks to the fact that I had to clean my buggy shaders.

But I have issues with resources management, only with Dx11: I now have sometimes an Ogre exception when I close the editor and destroy Ogre, because it seems that I still have unreferenced DX11 textures and shaders resources not freed.

In:

Code: Select all

D3D11DeviceResourceManager::~D3D11DeviceResourceManager()
{
    OgreAssertDbg(mResources.empty(),
        "Not all resources have been released! Are you holding on to a reference somewhere?");
    assert(gs_D3D11DeviceResourceManager == this);
    gs_D3D11DeviceResourceManager = NULL;
}

It happens when I change game and so reset and recreate the resources it seems, but I don't have any issue with DX9, only with DX11.

I spent several weeks trying to pinpoint what could cause the issue but I still don't have any idea.
Ogre experts, have you some ideas of things I could do wrong and where to look? Or any debug strategy?
S.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
paroj
OGRE Team Member
OGRE Team Member
Posts: 2251
Joined: Sun Mar 30, 2014 2:51 pm
x 1227

Re: DX11 closing assert: "Not all resources have been released!"

Post by paroj »

did you try printing the resource names in mResources?

User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

Yes, the resources are a shader microcode applied to a 3D object as well as the shader textures.
s.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
rpgplayerrobin
Orc Shaman
Posts: 792
Joined: Wed Mar 18, 2009 3:03 am
x 452

Re: DX11 closing assert: "Not all resources have been released!"

Post by rpgplayerrobin »

We had a post about this previously as well: viewtopic.php?p=552818#p552818
It is a very complicated issue and it sometimes still comes up in my game, where I have to make special user code to fix it again.

When you have destroyed all your user content (entitys, manual objects, custom/cloned materials, etc), and that you only have the resource managers left to unload, first use this code:

Code: Select all

#define FIND_DIRECT3D11_DEBUG_RESOURCE_CRASH
#ifdef FIND_DIRECT3D11_DEBUG_RESOURCE_CRASH
	// https://forums.ogre3d.org/viewtopic.php?p=552818#p552818
	// Get all resources into a list
	CList<ResourcePtr> tmpResources;
	ResourceManager::ResourceMapIterator tmpResourceIterator = MaterialManager::getSingleton().getResourceIterator();
	while (tmpResourceIterator.hasMoreElements())
	{
		ResourcePtr tmpResourcePtr = tmpResourceIterator.getNext();
		tmpResources.Add(tmpResourcePtr);
	}
	ResourceManager::ResourceMapIterator tmpItr = GpuProgramManager::getSingleton().getResourceIterator();
	if (tmpItr.begin() == tmpItr.end())
		tmpItr = HighLevelGpuProgramManager::getSingleton().getResourceIterator();
	for (ResourceManager::ResourceMapIterator::const_iterator i = tmpItr.begin(); i != tmpItr.end(); ++i)
	{
		const ResourcePtr tmpResourcePtr = i->second;
		tmpResources.Add(tmpResourcePtr);
	}
#endif

Also, make sure that all your custom meshes (that you have cloned or that you have created manually) that you have created should also before the code above be destroyed correctly, with this code to reset their materials:

Code: Select all

	// Clear the material of the mesh (otherwise it can actually stay as a referense, making Direct3D11 crash on debug on exit)
	for (size_t n = 0; n < resource->getNumSubMeshes(); n++)
	{
		SubMesh* tmpSubMesh = resource->getSubMesh(n);
		tmpSubMesh->setMaterial(NULL);
	}

When you have destroyed the resource groups (which should now in theory make ALL your content be unloaded), use this code:

Code: Select all

#ifdef FIND_DIRECT3D11_DEBUG_RESOURCE_CRASH
	// Remove all resources with only one use count
	for (int i = 0; i < tmpResources.Size(); i++)
	{
		ResourcePtr& tmpResource = tmpResources[i];
		if (tmpResource.use_count() == 1 ||
			tmpResource->getGroup() == "OgreInternal")
			tmpResources.Remove(i--);
	}

// The resources left here will only be the ones still in D3D11DeviceResourceManager::(~)D3D11DeviceResourceManager.
// Find them in your user code and fix them.
tmpResources.Clear(); // Debug this line here.
#endif

Debug the line where it says "Debug this line here" and see what resources are still used somewhere in your application/user code.

The CList class is only a wrapper of std::vector, and its "Add" function is the same as "push_back" and its "Remove" function is defined as this:

Code: Select all

// Removes a list element
template <class T>
void CList<T>::Remove(int listNum)
{
	// Delete the list object
	std::vector<T>::iterator del = m_list.begin();
	del += listNum;
	m_list.erase( del );
}

If I were you, I would go through the list and maybe post them here in case it might help you get rid of the RTShader resources that you mentioned were left in the other post.

User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

Thanks a lot, I will try this right now.
(btw I'm not using RTShader at all now, so I guess the issue is on me).

S.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

I also have difficulties keeping a consistent resources list:

In the editor, users can delete files inside directories in Windows, and when going back to the tool I detect if a file is added, modified or removed.
If yes, I'm importing or updating assets.
To refresh the resources, I'm doing this:

Code: Select all

Ogre::ResourceGroupManager::getSingletonPtr()->clearResourceGroup(game->gameName);
Ogre::ParticleSystemManager::getSingletonPtr()->removeTemplatesByResourceGroup(game->gameName);
Ogre::ResourceGroupManager::getSingletonPtr()->initialiseResourceGroup(game->gameName);

And I noticed that deleted assets (like a .mesh) are not removed from the resources list, and sometimes :

Code: Select all

 Ogre::ResourceGroupManager::getSingletonPtr()->resourceExists(gameName, assetName))

gives me a false positive.

What is the proper way of refreshing/updating the resources files list of a resource location?
S.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

Specifically, when I detect that a source file is removed by the user, for example "qiqi.fbx", I'm deleting the exorted .mesh and I'm trying to remove the resource from the resources list:

Code: Select all

Ogre::ResourceGroupManager::getSingletonPtr()->undeclareResource(meshName, Game::getSingletonPtr()->gameName);
Ogre::ResourceGroupManager::getSingletonPtr()->deleteResource(meshName, Game::getSingletonPtr()->gameName);
boost::filesystem::remove(filenameMat);

But, in certain case, just after that if I do:

Code: Select all

bool tttt = Ogre::ResourceGroupManager::getSingletonPtr()->resourceExists(Game::getSingletonPtr()->gameName, "qiqi.mesh");

I get true.

Is there anything preventing a resource to be removed from the resource list?
S.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
rpgplayerrobin
Orc Shaman
Posts: 792
Joined: Wed Mar 18, 2009 3:03 am
x 452

Re: DX11 closing assert: "Not all resources have been released!"

Post by rpgplayerrobin »

That sounds like a nightmare.
I have not attempted to do such things in my code to allow users to delete files and that it gets updated in the game.

If I were you, I would debug the code completely and see why the mesh is still in the resource group after you have attempted to remove it.

User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

I'm now often crashing, I think, in DirectX11 itself I think. The code doesn't assert with resources anymore, though with your method I see that all shadow casters shaders are still present in the resources after deleting everything.

So, when users add or modify a source 3D asset in fbx, the application converts them in .mesh using a slightly modified version of Assimp loader (I only modified the material generation) that saves a .mesh to disk.
And, even if I don't save the .mesh at all, only evaluating the createSubMesh() method, and especially the createIndexBuffer part, seems to often crash the application on Quit. Very often, but not always :/

After the mesh is created (and saved), I reckon I don't need it, so I remove it from Ogre like this at the end of Assimp loader convert method:

Code: Select all

// clean up
for (auto mesh : mMeshes)
 {
      Ogre::MeshManager::getSingletonPtr()->remove(mesh);
 }

Is it the right way to do it?

What could I do to find what causes this issue? I spent weeks doing random things without any luck, and I'm quite desperate :/

S.

http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
rpgplayerrobin
Orc Shaman
Posts: 792
Joined: Wed Mar 18, 2009 3:03 am
x 452

Re: DX11 closing assert: "Not all resources have been released!"

Post by rpgplayerrobin »

I have similar code myself, where I create a new mesh, save it to disk and then completely unload and remove it from the application.

My code looks somewhat like this:

Code: Select all

// Create the mesh
MeshPtr tmpMeshPtr = MeshManager::getSingleton().createManual(CGeneric::GenerateUniqueName(), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

// Create submeshes of it and stuff here

// Export the new mesh
MeshSerializer tmpMeshExport;
tmpMeshExport.exportMesh( tmpMeshPtr.get(), outputPath );

// Destroy the mesh
app->m_Generic->Destroy(tmpMeshPtr);

The function to destroy the mesh looks like this:

Code: Select all

// Destroys a resource
void CGeneric::Destroy(MeshPtr& resource)
{
	// Check if the resource is invalid
	if (!resource)
		// Return the function, we are done
		return;

// Clear the material of the mesh (otherwise it can actually stay as a referense, making Direct3D11 crash on debug on exit)
for (size_t n = 0; n < resource->getNumSubMeshes(); n++)
{
	SubMesh* tmpSubMesh = resource->getSubMesh(n);
	tmpSubMesh->setMaterial(NULL);
}

// Destroy the mesh
String tmpStr = resource->getName();
MeshManager::getSingleton().unload( tmpStr );
MeshManager::getSingleton().remove( tmpStr );
resource.reset();

// Check if the mesh still exists
if( MeshManager::getSingleton().resourceExists( tmpStr ) )
	// Show a message to the user
	ShowMessage("CGeneric::Destroy, The removal of a resource failed, the resource is still in use somewhere else.");
}
rpgplayerrobin
Orc Shaman
Posts: 792
Joined: Wed Mar 18, 2009 3:03 am
x 452

Re: DX11 closing assert: "Not all resources have been released!"

Post by rpgplayerrobin »

only evaluating the createSubMesh() method, and especially the createIndexBuffer part, seems to often crash the application on Quit. Very often, but not always :/

This sounds like you are using an invalid pointer or a null pointer somewhere. That creates unexpected behavior and can cause the application to crash almost anywhere else in the code randomly (but often in the same location in the code for some reason).
Have you tried what is actually causing it to crash there? Remove code until you find the culprit.
I also use createIndexBuffer in multiple places in my application in my user code, so if it crashes only when you use it, the code you use might be invalid somehow? If you can reproduce that the code that has to do with createIndexBuffer actually is the culprit, post it here and I can see if it looks correct.

User avatar
suny2000
Halfling
Posts: 89
Joined: Sun Sep 06, 2009 12:36 pm
x 18

Re: DX11 closing assert: "Not all resources have been released!"

Post by suny2000 »

I'm always crashing when Ogre unload Directx11 renderer, and it seems to crash in a Dx11 dll.
The crash only happens when I convert a fbx to .mesh with Assimp loader, and only with Dx11, never with Dx9, even if I'm not using the mesh in the app.

The code from Assimp loader:

Code: Select all

    // now begin the object definition
    // We create a submesh per material
    Ogre::SubMesh* submesh = mMesh->createSubMesh(name + Ogre::StringConverter::toString(index));

// prime pointers to vertex related data
aiVector3D *vec = mesh->mVertices;
aiVector3D *norm = mesh->mNormals;
aiVector3D *uv = mesh->mTextureCoords[0];
aiVector3D *tang = mesh->mTangents;
bool pipo = mesh->HasTangentsAndBitangents();
aiVector3D* binorm = mesh->mBitangents;
//aiColor4D *col = mesh->mColors[0];

// We must create the vertex data, indicating how many vertices there will be
submesh->useSharedVertices = false;
submesh->vertexData = new Ogre::VertexData();
submesh->vertexData->vertexStart = 0;
submesh->vertexData->vertexCount = mesh->mNumVertices;
submesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;

// We must now declare what the vertex data contains
Ogre::VertexDeclaration* declaration = submesh->vertexData->vertexDeclaration;
static const unsigned short source = 0;
size_t offset = 0;
offset += declaration->addElement(source,offset,Ogre::VET_FLOAT3,Ogre::VES_POSITION).getSize();

if (norm)
{
    offset += declaration->addElement(source,offset,Ogre::VET_FLOAT3,Ogre::VES_NORMAL).getSize();
}

if (uv)
{
    offset += declaration->addElement(source, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES).getSize();
}

if (tang)
{
    offset += declaration->addElement(source, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT).getSize();
}

Ogre::String materialName = mBasename + "_" + Ogre::StringConverter::toString(index);
   submesh->setMaterial(NULL);

// We create the hardware vertex buffer
Ogre::HardwareVertexBufferSharedPtr vbuffer =
    Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(declaration->getVertexSize(source), // == offset
    submesh->vertexData->vertexCount,   // == nbVertices
    Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);

aiMatrix4x4 aiM = mNodeDerivedTransformByName.find(pNode->mName.data)->second;

aiMatrix4x4 normalMatrix = aiM;
normalMatrix.a4 = 0;
normalMatrix.b4 = 0;
normalMatrix.c4 = 0;
normalMatrix.Transpose().Inverse();

// Now we get access to the buffer to fill it.  During so we record the bounding box.
float* vdata = static_cast<float*>(vbuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
for (size_t i=0;i < mesh->mNumVertices; ++i)
{
    // Position
    aiVector3D  vect(vec->x, vec->y, vec->z);
    vect = aiM * vect;


    Ogre::Vector3 position( vect.x, vect.y, vect.z );
    *vdata++ = vect.x;
    *vdata++ = vect.y;
    *vdata++ = vect.z;
    mAAB.merge(position);
    vec++;

    // Normal
    if (norm)
    {
        vect.x = norm->x;
        vect.y = norm->y;
        vect.z = norm->z;

        vect *= normalMatrix;
        vect = vect.Normalize();

        *vdata++ = vect.x;
        *vdata++ = vect.y;
        *vdata++ = vect.z;
        norm++;
    }

    // uvs
    if (uv)
    {
        *vdata++ = uv->x;
        *vdata++ = uv->y;
        uv++;
    }

    // Tangent
    if (tang)
    {
        *vdata++ = tang->x;
        *vdata++ = tang->y;
        *vdata++ = tang->z;
        tang++;
    }
}

vbuffer->unlock();
submesh->vertexData->vertexBufferBinding->setBinding(source,vbuffer);

if (mesh->mNumFaces == 0)
    return true;
aiFace *faces = mesh->mFaces;

// Creates the index data
submesh->indexData->indexStart = 0;
submesh->indexData->indexCount = mesh->mNumFaces * 3;

if (mesh->mNumVertices >= 65536) // 32 bit index buffer
{
        submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
                Ogre::HardwareIndexBuffer::IT_32BIT, submesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);

        Ogre::uint32* indexData = static_cast<Ogre::uint32*>(submesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));

        for (size_t i=0; i < mesh->mNumFaces;++i)
        {
            for (int j = 0; j < 3; j++)
                *indexData++ = faces->mIndices[j];

                faces++;
        }
}
else // 16 bit index buffer
{
    submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
        Ogre::HardwareIndexBuffer::IT_16BIT, submesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);

    Ogre::uint16* indexData = static_cast<Ogre::uint16*>(submesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));

    for (size_t i = 0; i < mesh->mNumFaces; ++i)
    {
        for (int j = 0; j < 3; j++)
            *indexData++ = faces->mIndices[j];

        faces++;
    }
}
submesh->indexData->indexBuffer->unlock();

return true;
}
http://bulostudio.com: website and devlog of a small indie studio working on SHMUP CREATOR
https://twitter.com/bulostudio : follow me on twitter!
rpgplayerrobin
Orc Shaman
Posts: 792
Joined: Wed Mar 18, 2009 3:03 am
x 452

Re: DX11 closing assert: "Not all resources have been released!"

Post by rpgplayerrobin »

It is impossible to know from that code if anything went wrong.
You can go out of bounds with all of those array pointers that was returned by Assimp, but as I don't have access to the mesh or Assimp (I don't use it in my game, and I cannot even compile it in debug for some reason because of how CMake is creating the project), it is hard for me to reproduce it using this code.
It can be even such a small issue like that "mesh->mTextureCoords[0];" does not exist. But since I don't have the data returned from Assimp it is hard for me to debug anything.

To debug it, simply remove code in that function until it no longer crashes, then you will know exactly which row and/or function that is causing it.

Otherwise, try to make a small code that I can reproduce myself, then I can probably fix it. To do that, you must create the "aiVector3D *vec" and such yourself in code to show a completely reproducible code that does not need anything else than just itself to crash.