Archived

This topic is now archived and is closed to further replies.

Memory Management in 3d Engines

This topic is 5106 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I''ve got some questions regarding the memory management in 3d engines. From what I''ve learnt, there are 3 storage spaces (directx): System''s Memory, AGP Bus Memory and GPU Video Memory. I wonder how data is structured and buffered in these different systems... If you load a large object (ie, Level), how do you organize the geometry data? Do you first load it into the System''s Memory, and only afterwards split it into dynamic and static vertex buffers? Or do you directly split the data into static and dynamic vertex buffers during the load process? Some ''data handling pipeline'' would help me

Share on other sites
I can''t help, you but I just want to say: great topic! I also want to know how it''s done.

Share on other sites
For very large scenes, you might not even be able to load the entire thing at once. So, you could start out with allowing the scenes to be streamed and cache everything for what the current frame needs (all visible nodes from a tree perhaps?). When a node gets into view, you load it or you could have issued a pre-cache a bit before to reduce hick-ups. A node contains vertex buffers and face data which you upload to the GPU if possible and make sure as much as possible of the frame is up there. Just remember to use a lot of caching which is pretty obvious though. Let the engine be able to be lazy, not the developer

Share on other sites
The way I''ve organized it in my engine is:

                     Level File        (hard drive)                         |                                         |                load the entire map into memory                         |                   System Memory                         |                         |                for every piece of geometry, load into a dynamic vertex buffer (data is lost each frame)                         |               Dynamic Vertex Buffer (AGP Memory)                         |                         |      <   if data has been used over many frames > ------> store in Static Vertex Buffer (data is retained over many frames) (On-Card Video Memory)

In either case you have the vertex data in a vertex buffer and you render it from that buffer. I have 1 fixed size dynamic buffer (of several megabytes in size) that I fill with all vertex data for my engine. If vertex data is re-entered into th is buffer over many frames, it''s written to one of two (whichever hasn''t been used recently, to prevent read/write stalls) static buffers, and is instead read from there and not the dynamic buffer. This means that if a scene is small enough and static, this will automatically get maximum performance by putting everything in static buffers, but if the scene is dynamic or too large to fit in video memory, maximum consistent bandwidth usage is achieved when vertex data is moved to the card. Hope this makes sense!

Chris Pergrossi
My Realm | "Good Morning, Dave"

Share on other sites
thanks for your insight! from what I''ve learnt on developer.nvidia, vertexbuffers should be big enough (so around 2000 polygons), now I wonder, when you have a spatial partition tree like an octree you usually set the threshold to way below 2000. How do save the geometric data in such a tree (in its leaves)?

Share on other sites
Depedning on what you are using the tree for, you should set the subdivision limit differently. If you use it for collision detection, then your limit should indeed be much less than a few thousand polys. But if you use the tree for rendering (i.e. to assist frustum/occlusion culling, then a few thousand polys per leaf node is a good limit.

With some adjustments, you could use the same tree for both collision detection and rendering, but this will likely not be optimal, since there are other tradeoffs besides the subdivision limit - the two tasks have somewhat different optimal conditions.

Michael K.,
Co-designer and Graphics Programmer of "The Keepers"

We come in peace... surrender or die!

Share on other sites
Thanks! So I would set up 2 different trees, one for rendering / occlusion culling etc. and one for collision detection.

So (for rendering only) the pipeline would be like:

Load static geometry into System's Memory -> Start Octree/ABTree whatever creation -> Store the Vertices into Static Vertex Buffers in the leaves. Store indexed primitives in one big index buffer.

Now how would you organise the dynamic data? A hierarchical 'game-object' tree linked to the leaves / nodes of the tree (for the spatial location of the dynamic object), and one big dynamic vertex buffer. Now how do you distinguish the dynamic objects? Several index buffers for the objects, or the same index buffer as above?

[edited by - mux on May 31, 2004 3:01:04 PM]

[edited by - mux on May 31, 2004 3:16:32 PM]

Share on other sites
Well, if you implement a system similar to mine, the pipeline would go:

|
|
sort static geometry into whichever trees you need for rendering (store on the heap)
(this applies to rendering)
|
|
traverse the tree and add all 'visible' leafs to a dynamic vertex buffer (increment 'coherency' counter if data does not change)
|
|
< if the data has been visible for many frames, store in static buffer and reference that instead >

this whole system allows you to stream data from disk extremely well, as it encourages dynamic data and automatically optimizes usage if the data doesn't change over many frames (temporal-coherency).

You probably couldn't fit all your level data into one index buffer (besides, why would you want to?). If you dynamically fill an index buffer with vertex references, you can optimize your DrawIndexedPrimitive calls to minimize the number of batches you send to the card (i.e. put several leafs with the same render 'parameters' sequentially in the buffer, and render ALL the polygons in one call)

Chris Pergrossi
My Realm | "Good Morning, Dave"

edit: stupid brackets

[edited by - c t o a n on June 1, 2004 9:42:27 AM]

Share on other sites
Thanks for the help so far, ctoan your solution sounds pretty tasty!

quote:
Original post by c t o a n
...
sort static geometry into whichever trees you need for rendering (store on the heap)
...

Uhm sorry if I sound stupid, but I got another qeustion and I hope you could answer it, where do you store your dynamic geometry in your rendering framework?

[edited by - mux on June 1, 2004 1:02:55 PM]

Share on other sites
dynamic how? animated meshes, ''movers'', etc.? I seperate my static and dynamic geometry into different spatial trees in my scenegraph. The reason for this is I store the static geometry in a tree (usually an octree) and optimize it. I split any polygons that need splitting and the static geometry will render as fast as possible. In this tree, each leaf has something like:

vector3* vertices;
u16* polys;

on a basic level, thats how simple it is. My engine also allows streaming of data, so you could check if this leaf is visible, or if the neighbors of this leaf are visible, and if vertices == NULL or something similar, load the leaf from file into memory.

My dynamic geomtry then goes into another tree, usually MUCH smaller, which allows it to be modified. I use a non-uniform quadtree most of the time, which allows me to still cull most of the dynamic geometry away, but when it moves, the tree can be updated quite easily (and quickly) to reflect the new data.

A non-uniform quadtree, by the way, is a quadtree with non-uniform areas per node (so it doesn''t split down the middle). The tree splitting planes (which don''t actually ''split'' dynamic geometry, merely spatially classify it) are recalculated after a certain threshold is reached, such as there are too many dynamic objects in a single node, so adjust the planes to split them into different nodes.

Chris Pergrossi
My Realm | "Good Morning, Dave"

• 10
• 17
• 9
• 13
• 41