Replacing buffers problem

Piotrek

26-04-2015 22:19:51

Hi,

Very often, but not every frame I need to replace vertex and index buffers in SubMesh with new ones which contains new mesh data.
These new buffers are often much smaller or much bigger than previous.
This is my custom lod mechanism where new mesh data is generated dynamically (entity geometry changes very often) and old mesh data need to be removed from memory.
I am only replacing buffers because I don't want to allocated to many objects that will raise GarbageColletor too often.
In my current solution after few minutes I get exceptions. Mostly it is access violation exception or out of video memory exception (GPU-Z show only 400MB usage of 2GB).
So what I am doing wrong? If my approach is wrog how can I do it good ?
Can someone help me?

Currently I do it like this:

First I create Mesh with SubMesh
- For SubMesh i create new VertexData to which I inject cloned VertexDeclaration (that is prepared only once) and new VertexBufferBinding
- New buffers are created with flag HBU_STATIC_WRITE_ONLY and binded to SubMesh's vertexData and indexData

When mesh need to be updated (new lod level mesh is genereted), first I 'clean' SubMesh like this:
- reset current indexData's indexBuffer field and dispose current IndexBuffer
- unbind existing vertex buffer
- dispose current vertexBuffer
Then I create new buffers and attach them to SubMesh

Here is the code:

MeshPtr meshPtr = MeshManager.Singleton.CreateManual(name, mResourceGroup);
SubMesh subMesh = meshPtr.CreateSubMesh();
subMesh.useSharedVertices = false;
subMesh.vertexData = new VertexData(_vertexDeclaration.Clone(), new VertexBufferBinding());


public void ResetMesh(MeshPtr meshPtr)
{
Debug.Assert(meshPtr.NumSubMeshes == 1 || meshPtr.NumSubMeshes == 0);
if (meshPtr.NumSubMeshes > 0 && meshPtr.GetSubMesh(0).vertexData != null)
{
SubMesh submesh = meshPtr.GetSubMesh(0);

// Destroy IndexBuffer
submesh.indexData.indexCount = 0;
submesh.indexData.indexBuffer.Dispose();
submesh.indexData.indexBuffer = null;


// Destroy VertexBuffer
HardwareVertexBufferSharedPtr vertexBuffer = submesh.vertexData.vertexBufferBinding.GetBuffer(0);
VertexBufferBinding binding = submesh.vertexData.vertexBufferBinding;
submesh.vertexData.vertexCount = 0;
binding.UnsetBinding(0);
// binding.UnsetAllBindings();
submesh.vertexData.RemoveUnusedBuffers();
vertexBuffer.Dispose();
}
}


Exceptions I get:

Unhandled exception at 0x5F38AC50 (nvd3dum.dll) in SpaceTrek.exe: 0xC0000005: Access violation reading location 0x0000041C.

OGRE EXCEPTION(3:RenderingAPIException): Failed to DrawPrimitive : Out of video memory in D3D9RenderSystem::_render at D:\Mogre BUILD\MogreBuilder__Result_bugFixed\Main\OgreSrc\ogre\RenderSystems\Direct3D9\src\OgreD3D9RenderSystem.cpp (line 3139)

OGRE EXCEPTION(3:RenderingAPIException): Cannot restore D3D9 vertex buffer: Ran out of memory in D3D9HardwareVertexBuffer::createBuffer at D:\Mogre BUILD\MogreBuilder__Result_bugFixed\Main\OgreSrc\ogre\RenderSystems\Direct3D9\src\OgreD3D9HardwareVertexBuffer.cpp (line 264)

Beauty

27-04-2015 21:57:54

So what I am doing wrong?
Just an idea:
Fragmentation of the memory ... and somewhen you have so many small gaps that you get no block, which is big enough. Like fragmentation on a hard disk.

An other idea:
Possibly the removed sections of a ManualObject get not available again. Like dead memory.

An idea for the access violation exception:
Maybe this comes up by multi threading memory access. (Give pre-calculated data to the main thread.)
Possibly a wrapper generated manged class tries to access to an object or pointer inside of the unmanaged C++ library, which was just deleted.

You could try to use my binary bundle, which was build in debug mode. (Or build you own with MogreBuilder and adjusted config file.)
By this its possible to find errors more deeply inside of the code. You can debug the Ogre C++ code with the debug builds.


If my approach is wrog how can I do it good ?
Can someone help me?

I recommend to write a re-post in the Ogre main forum, because this is a mostly common Ogre topic (not very Mogre specific).
In the main forum are many people with good knowledge. So you can get useful ideas from other people.

If you can't solve the troubles at all:
Maybe Axiom is better in your case. It's a C# port of Ogre. Not with all features, but maybe it's enough.
Or switch to native Ogre in C++ with good community support, all new features, but without the sweet .NET framework.
It's not nice to "step down", but it's a choice. One Mogre user did it with his project. It was a pain at the first time, but later he said it was a good step for his project.

Good luck!

Piotrek

04-05-2015 12:35:36

Fragmentation of the memory ... and somewhen you have so many small gaps that you get no block, which is big enough. Like fragmentation on a hard disk.
You may be right. But how to confirm that?
And what about the code I use to clear old data (hardware buffer)? In your opinion is it correct ? Maybe I am forgeting to release something ?
What about OGRE_THREAD_SUPPORT flag? Is there sense to compile Mogre with diffrent value to try resovle my issue?
Is HBU_STATIC_WRITE_ONLY correct flag for buffer creating in my case ?
Possibly the removed sections of a ManualObject get not available again. Like dead memory.
Here I am not using ManualObject. But you mean that memory that was released (destroyed buffers) is not available again? Bug in driver ?
An idea for the access violation exception:
Maybe this comes up by multi threading memory access. (Give pre-calculated data to the main thread.)
Possibly a wrapper generated manged class tries to access to an object or pointer inside of the unmanaged C++ library, which was just deleted.

On separate thread I generate only array with vertex coordinates and array with indexes and put them to ConcurrentQueue. Then on main thread I take these arrays and generate buffers. So I don't think the problem lies in that.
You could try to use my binary bundle, which was build in debug mode. (Or build you own with MogreBuilder and adjusted config file.)
By this its possible to find errors more deeply inside of the code. You can debug the Ogre C++ code with the debug builds.

I think I am using your binary bundle. It was published on that forum, ver. 1.7.4 right?
Also the exception occurs in nvd3dum.dll and I couldn't find pdb for that dll :(

Beauty

04-05-2015 19:13:07

You may be right. But how to confirm that?
And what about the code I use to clear old data (hardware buffer)? In your opinion is it correct ? Maybe I am forgeting to release something ?
What about OGRE_THREAD_SUPPORT flag? Is there sense to compile Mogre with diffrent value to try resovle my issue?
Is HBU_STATIC_WRITE_ONLY correct flag for buffer creating in my case ?

I'm sorry, I can't help you on this.
But you have good chances to get replies in the Ogre main forum. Just ask there.

But you mean that memory that was released (destroyed buffers) is not available again?
It's just a theoretical idea. How it is in practice I don't know.
An answer could be found by analysis of the ManualObject code (Ogre C++ code) or by asking in the main forum.

I think I am using your binary bundle. It was published on that forum, ver. 1.7.4 right?
Yes, I published bundles for 1.7.4 here.
The second package on that post is a debug build.

Also the exception occurs in nvd3dum.dll and I couldn't find pdb for that dll :(
That's bad. The name looks like "nVidia".


Sorry, my knowdedge is at the end.
I really recommend to write a post in the Ogre main forum.
The most text you can copy and paste from your posts here.

Piotrek

21-05-2015 22:18:47

Thanks anyway:)
I will try on Ogre help forum.

Beauty

30-05-2015 14:58:53

If you created a post in the main forum, you can give us the link.