[SLVD] vertex buffer ran out of memory on huge objects count

Problems building or running the engine, queries about how to use features etc.
Post Reply
Spectre
Gnoblar
Posts: 16
Joined: Mon May 04, 2015 4:45 pm
x 2

[SLVD] vertex buffer ran out of memory on huge objects count

Post by Spectre »

Hello, I have to load huge amount of objects, which causes big use of ram, and eventually ogre crashes with hardware vertex buffer exception:
"OGRE EXCEPTION(3:RenderingAPIException): Cannot restore D3D9 vertex buffer: Ran out of memory in D3D9HardwareVertexBuffer::createBuffer"

I used raw manual objects at a time, and was able to load approx 80% of the scene before the crash hit me at 1.7gb ram used. I thought that I should convert them to meshes, but after doing that I was able to load only half as much before hitting exception at again approx 1.7gb of ram.
I noted it usually happens at 1.7gb, if I disable loading of textures I was able to load more objects before same exception happens at the same amount of ram. Same happens in OpenGL too, but somehow it uses much less ram for meshes - exception happens at approx same amount of data, though application itself weights just 500mb at that moment.
My first thought was scene just doesn't fit into my 256mb videocard, but exactly same happened on a system with 1gb video memory - at approx 1.7gb ram used. Maybe there is a way to increase hardware buffer size? I couldn't find anything on topic.
Another curious note is that crash happens even if I don't actually add converted meshes to the scene - just fill manual object with data, convert it to mesh, delete manual object, and proceed to next without creating entity into scene, it seem to always depend on ram used.
Last edited by Spectre on Fri May 08, 2015 1:47 am, edited 1 time in total.
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: vertex buffer ran out of memory on huge objects count

Post by dark_sylinc »

2GB is the limit for user space 32-bit processes. Due to memory fragmentation, allocations may fail long before getting close to the 2GB limit.

Switch your application to 64-bit, or lower your memory consumption via optimizations and compression schemes.
Spectre
Gnoblar
Posts: 16
Joined: Mon May 04, 2015 4:45 pm
x 2

Re: vertex buffer ran out of memory on huge objects count

Post by Spectre »

Whoa, I thought it was 4gb on 32bit? Thanks, I'll try moving onto 64bit, will I need to change ogre libs too, or they can compile either way?
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: vertex buffer ran out of memory on huge objects count

Post by dark_sylinc »

Spectre wrote:Whoa, I thought it was 4gb on 32bit?
The other 2gb half is reserved for kernel space. There are ways to shift this to 3GB / 1GB (OS global option) or use the large address aware when running behind a 64-bit OS.
But they come with horrible tradeoffs.

Considering the huge amounts of memory you're using, you should really use 64-bit and not those hacks.
Spectre wrote:will I need to change ogre libs too, or they can compile either way?
Ogre can be compiled from source with 64-bit compilers and will work fine, I don't know if the prebuilt SDKs come in 64-bit flavours though.
Spectre
Gnoblar
Posts: 16
Joined: Mon May 04, 2015 4:45 pm
x 2

Re: vertex buffer ran out of memory on huge objects count

Post by Spectre »

Finds out, precompiled libraries are bit-dependent, and I use some of third party's which are unavailable in 64bit for me, so most appealing option is not available. I tried large addres aware flag, but somehow ogre began to use even more ram, and blew at 3gb at just 60% of the scene.

Since scene almost fits in normal conditions, maybe there's a way to reduce meshes size, or more continuously pack them in memory? Rest of my everything weights a lot less than meshes do, for example: whole textures loaded add only 250mb to the ram. I heard about special compile flag that removes all LOD related code from ogre and meshes, what else techniques to reduce mesh size are out there, and how much size reduction can they achieve?

Right now I'm investigating manual mesh creation through vertex buffers, that can help reuse vertex data through indexing, and also since I only use vertex colors and uv, drop unused stuff like edge lists, shadows and normals. I copied code from this tutorial and it works fine, so I tried to modify it a bit: with memory optimisations in mind, I tried to reuse most obvious bit, and saved configured vertex declaration to be used by all meshes:

Code: Select all

	static Ogre::VertexDeclaration* decl = 0;
	static size_t offset1 = 0;
	static size_t offset2 = 0;
	if( !decl ) {
		decl = Ogre::HardwareBufferManager::getSingleton().createVertexDeclaration();

		// 1st buffer
		decl->addElement( 0, offset1, Ogre::VET_FLOAT3, Ogre::VES_POSITION );
		offset1 += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 );
		decl->addElement( 0, offset1, Ogre::VET_FLOAT3, Ogre::VES_NORMAL );
		offset1 += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 );

		// 2nd buffer
		decl->addElement( 1, offset2, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE );
		offset2 += Ogre::VertexElement::getTypeSize( Ogre::VET_COLOUR );
	}
But, this causes crash on second run - first mesh is succesfully added to the scene, but creation of the second causes "VertexBufferBinding::getBuffer - No buffer is bound to that index" exception on last bit of code, where Mesh::load() method is called. I tried two different replacements, but they both "work" just right until the load called for the second mesh:

Code: Select all

	//first
	Ogre::HardwareBufferManager::getSingleton().destroyVertexDeclaration(
					msh->sharedVertexData->vertexDeclaration );
	msh->sharedVertexData->vertexDeclaration = decl;

	//second, moved down through code so bind structure already exists
	msh->sharedVertexData = new Ogre::VertexData( decl, bind );
If I create new declaration for each mesh, it works fine. Documentations says buffers indexes are locally bound, and buffers may be reused, why do I need to create new vertex declaration for each mesh?


//Also, I tested again in OpenGL, and there app uses a LOT less ram, crash happens at just 700mb point, through approx same amount of data is loaded at this point. Why is ram usage so ambiguous in OpenGL?
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: vertex buffer ran out of memory on huge objects count

Post by dark_sylinc »

The D3D9 API will keep a shadow copy of the data uploaded to GPU in case there is a device lost event.
OpenGL deals with this differently with different tradeoffs (also depends on the driver implementation).

As for approaches to reducing size, in Ogre 2.1 we added the VET_HALF formats and introduced QTangent conversion.
Most of the time 16-bit floats are enough to represent information, and QTangents encode normal, tangent and binormal information into just 8 bytes per vertex.

You may want to take a look at the code in the 2.1 branch to see what you can port back to 1.x that could be of use to you (or use 2.1 for your work instead; which by the way, has much lower memory consumption overall; but beware 2.1 is WIP)

Also, big meshes (vertex count > 65535) means you need 32-bit indices. Spliting these meshes into multiple submeshes (so that each chunk <= 65535) trades off a little of CPU draw call overhead for halving the required size of the index buffer.
If I create new declaration for each mesh, it works fine. Documentations says buffers indexes are locally bound, and buffers may be reused, why do I need to create new vertex declaration for each mesh?
Ogre 1.x has two modes: Shared vertex buffers and non-shared vertex buffers.
In the former, you create one vertex buffer in the mesh and leave the submesh' vertex buffer as a null pointer; in the latter, you leave the vertex buffer in the mesh as a null pointer, and create a vertex buffer per submesh.
Index buffers are always per submesh.
I recommend using non-shared vertex buffers though. It never did what it was intended (reduce draw call overhead and memory footprint), and is the least tested codepath. It also made things more confusing (like you are confused just now).
It was also removed from the 2.x branch for these reasons.
Spectre
Gnoblar
Posts: 16
Joined: Mon May 04, 2015 4:45 pm
x 2

Re: vertex buffer ran out of memory on huge objects count

Post by Spectre »

Thanks for input, it was a triumph. //I'm making a note here - huge succes.
Using meshes built from buffers with shared index data between submeshes, I was able to achieve almost 60% mesh size reduction, even without 16bit floats, it finished loading at 1.2gb. I do need to create new vertex declarations for each mesh though, but it appears it didn't mattered too much.
That was rather dope expirience, pushing old games this much past the limit.
Spectre
Gnoblar
Posts: 16
Joined: Mon May 04, 2015 4:45 pm
x 2

Re: [SLVD] vertex buffer ran out of memory on huge objects c

Post by Spectre »

Hmm, since fps was below okay, I created a simple zone subdivision, with a separated scene nodes for each chunk of objects, which gets removed from scene graph when camera is far away from that cluster. But after testing, I found out that after full loading fps is just generally low, and depends on entities actually existing, rather than their presence in the graph. If I only load all of the resources without creating entities, I still have maximum fps in empty scene, but if I create entities even without attaching them to the nodes, they burdening down my fps, in the still empty scene, why that happens?
Post Reply