Data Design for Scene Graphs

Published October 14, 2014
Advertisement

CppCon 2014


In case you haven't heard about, all of the sessions from CppCon 2014 are being released on the CppCon YouTube Channel. This is a fantastic way for you to catch up on the latest and greatest things that people are doing with C++ (especially modern C++), and the price is about as good as it gets. There are over 100 sessions, and they are being posted as they are processed, so be sure to check back periodically.

This post is going to be related to one of the keynote talks by Mike Acton titled "Data Oriented Design and C++". The talk itself was pretty good, with the delivery only suffering from slightly jumping from topic to topic (he is also more of a C fan than C++, but nobody is perfect smile.png ). However, the concept and message that Mr. Acton was delivering came through loud and clear - you should be paying close attention to your data and how it is used. His examples showed his clear understanding and (what I consider to be) unique way of diagnosing what is going on. One of his examples was about the scene graph node class in Ogre3D, which he subsequently cut into and showed how he would change things.

Hieroglyph 3 Scene Graph


That got me thinking about the scene graph in Hieroglyph 3. This system is probably one of the oldest designs in the whole library, and has its origins in the Wild Magic library by Dave Eberly. The basic idea is to have a spatial class to represent your 3D objects (called Entity3D), and a node class which is derived from the spatial class (called Node3D) but which adds the scene graph connectivity. This system has worked for me for ages, and is a simple, clear design that is easy to reason about (at least to me it is...).

Prompted by the talk I mentioned above, I wanted to take a closer look at the data contained within my scene graph classes, and try to see if I am wasting memory and/or performance in an obvious way. I never tried to "optimize" this system, since it never showed up as a significant bottleneck before, but I think it will serve as a nice experiment - and it will let me explore some of the techniques for drilling into this type of information.

I am going to spread this analysis over a few blog posts, mostly so that I can provide the appropriate amount of coverage to each particular topic that I touch on. For this post, we will simply start out by identifying one easy to use tool in Visual Studio - the unsupported memory layout compiler flags. There have been many instances where Microsoft has mentioned two different memory layout flags that will dump layout info about an object to the output window in VS: /d1reportSingleClassLayoutCLASSNAME and /d1reportAllClassLayout. They do what it sounds like - basically just report the size of one or all classes in the translation unit being compiled. You can add this to the 'Command Line' entry in the property file of the CPP file containing the desired class, and then compile only that translation unit by selecting it and pressing CTRL+F7. Be sure to be consistent in how you test as well - using release mode is probably the most sensible, and stick to either 32- or 64-bit compilation.

The output can be a bit verbose, but within it you will find a definition for your class along with a byte offset for each member. An example is shown here:1> class Entity3D size(396):1> +---1> 0 | {vfptr}1> 4 | Vector3f m_vTranslation1> 16 | Matrix3f m_mRotation1> 52 | Vector3f m_vScale1> 64 | Matrix4f m_mWorld1> 128 | Matrix4f m_mLocal1> 192 | m_bPickable1> 193 | m_bHidden1> 194 | m_bCalcLocal1> | (size=1)1> 196 | m_pParent1> 200 | ?$vector@PAVIController@Glyph3@@V?$allocator@PAVIController@Glyph3@@@std@@ m_Controllers1> 212 | ?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@ m_Name1> 236 | EntityRenderParams m_sParams1> 320 | ParameterContainer Parameters1> 336 | Sphere3f m_ModelBoundingSphere1> 356 | Sphere3f m_WorldBoundingSphere1> 376 | CompositeShape CompositeShape1> 392 | m_pUserData1> +---
There are a few things you can see right away without trying too hard:

  1. The object is 396 bytes big
  2. The class is part of an inheritance hierarchy, since it has a vfptr
  3. There is some wasted space in the middle of the object due to alignment requirements

After seeing this, I started to dig in to what is really needed from these classes, and then started to identify a few different strategies for simplifying and reducing their sizes. More on those results in the next post or two!

One more thing...


On October 1st, I was re-awarded as a Visual C++ MVP! That marks six years running (yay!). Whenever I hit a milestone like this, I always like to reflect on how I got to that point - and GameDev.net is always a strong contributor to where I am today. I truly learned a ton from the people in this community, and I get a great deal of satisfaction from trying to contribute back - so thank you all for being part of something great!
6 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement