Vector3 member initialization

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
Peet
Gnoblar
Posts: 3
Joined: Thu Nov 25, 2010 1:21 am

Vector3 member initialization

Post by Peet »

Personally, when I call the default constructor of a class, I make the assumption that that class' members are now initialized to a sane non-NaN value. I believe this places me in same category as the general programming public - it strikes me a pretty reasonable assumption. Similarly, the Ogre coding guidelines state All class variables should be initialized to a sane value in the constructor.

So why is the Vector3 class a blatant exception to this? People in #ogre3d have been making the argument that leaving initialization to the users of the library has a performance advantage, but the constructor is inline which means any resultant multiple assignments will be optimized out by any sane compiler. Even if that were a valid argument, the complete lack of documentation of this fact makes it a very notable pitfall for developers using Ogre.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413

Re: Vector3 member initialization

Post by dark_sylinc »

Peet wrote:People in #ogre3d have been making the argument that leaving initialization to the users of the library has a performance advantage, but the constructor is inline which means any resultant multiple assignments will be optimized out by any sane compiler.
No.
Anything where the initialization is obfuscated, may not get inlined and initialization can't be optimized out.

Consider this simple DLL example:

Code: Select all

__declspec(dllexport) Ogre::Vector3 returnMyVector() { return Ogre::Vector3(); }
When this function gets called from an exe to the dll, the compiler has no way to know at compile time what happens to the returned values or what is being returned. There's little chance of optimization.

Furthermore, floating point optimizations are much less aggressive than one would think, compared to integer optimizations or any other kind (which is so, in order to preserve precision). Even obvious optimizations like a = a / 2.0f may not be optimized to a = a * 0.5f because in floating point, this isn't actually the same.
Peet wrote:Even if that were a valid argument, the complete lack of documentation of this fact makes it a very notable pitfall for developers using Ogre.
Fair point. Advanced users of 3D graphic engines assume that things like Vectors and Quaternions aren't usually initialized (the latter is initialized in Ogre); so we forget programmers new into 3D programming don't know this.
Peet
Gnoblar
Posts: 3
Joined: Thu Nov 25, 2010 1:21 am

Re: Vector3 member initialization

Post by Peet »

dark_sylinc wrote:
Peet wrote:People in #ogre3d have been making the argument that leaving initialization to the users of the library has a performance advantage, but the constructor is inline which means any resultant multiple assignments will be optimized out by any sane compiler.
No.
Anything where the initialization is obfuscated, may not get inlined and initialization can't be optimized out.

Consider this simple DLL example:

Code: Select all

__declspec(dllexport) Ogre::Vector3 returnMyVector() { return Ogre::Vector3(); }
When this function gets called from an exe to the dll, the compiler has no way to know at compile time what happens to the returned values or what is being returned. There's little chance of optimization.
This is a bit of a ridiculous argument...If the constructor of Vector3 is called inside the ogre so/dll from the game (tip: it's not), 3 additional assignments are not the primary optimization concern here :wink:
dark_sylinc wrote:Furthermore, floating point optimizations are much less aggressive than one would think, compared to integer optimizations or any other kind (which is so, in order to preserve precision). Even obvious optimizations like a = a / 2.0f may not be optimized to a = a * 0.5f because in floating point, this isn't actually the same.
How is this even relevant? Only assignment is in question here; mentioning other operations is just a red herring....
dark_sylinc wrote:Advanced users of 3D graphic engines assume that things like Vectors and Quaternions aren't usually initialized (the latter is initialized in Ogre); so we forget programmers new into 3D programming don't know this.
Telling me that a similar class DOES initialize its members doesn't exactly strengthen your justification for not initializing a vector in its default ctor. This sort of inconsistency doesn't only affect "programmers new into 3D programming", and I would definitely appreciate it if you would not assume that someone whose views do not match your own is inexperienced.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: Vector3 member initialization

Post by jacmoe »

The difference is probably that Vector3 is meant to be treated like a primitive type.
Just like int, float, etc.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
so0os
Bugbear
Posts: 833
Joined: Thu Apr 15, 2010 7:42 am
Location: Poznan, Poland
x 33

Re: Vector3 member initialization

Post by so0os »

Does float get initialised whgen you declare it? What's the point?!?! if you need a vector, i think you want to use it, and if you do you get a warning.
Sos Sosowski :)
http://www.sos.gd
Peet
Gnoblar
Posts: 3
Joined: Thu Nov 25, 2010 1:21 am

Re: Vector3 member initialization

Post by Peet »

jacmoe wrote:The difference is probably that Vector3 is meant to be treated like a primitive type.
Just like int, float, etc.
This is sensible; all I ask is that it be noted in the doxygen documentation.
so0os wrote:Does float get initialised whgen you declare it? What's the point?!?! if you need a vector, i think you want to use it, and if you do you get a warning.
Vector3 is a class, not a built in type. Arguing implicitly that it is to be treated like a primitive type is not valid (and there is no warning that a Vector3 is uninitialized since it just calls the empty default constructor).
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413

Re: Vector3 member initialization

Post by dark_sylinc »

Peet wrote:This is a bit of a ridiculous argument...If the constructor of Vector3 is called inside the ogre so/dll from the game (tip: it's not), 3 additional assignments are not the primary optimization concern here :wink:
It was an example. It extends to any DLL function that returns Vector3, any Vector3 initialized in the exe but passed to the DLL, or any function that accepts a reference or pointer as an argument.
By the way, it's not just "3 additional assignments". It's 3 additional assignments per Vector3 declaration (there are too many) per frame. And half or more of them won't be optimized away sadly.
Peet wrote:How is this even relevant? Only assignment is in question here; mentioning other operations is just a red herring....
Again, an example. If the compiler can't be guaranteed the value is uninitialized, it has to shift some bits of instruction in some situations to adjust to this. It holds more important when passing a (const or not) reference, than when passing by copy.
Peet wrote:This sort of inconsistency doesn't only affect "programmers new into 3D programming", and I would definitely appreciate it if you would not assume that someone whose views do not match your own is inexperienced.
I chose carefully my words when phrasing it, so that it would be clear that I didn't say "inexperience programmer". Even the most experienced of programmers can't know what are the common uses and traditions in a certain field, this case 3D graphics; until he gets fond with it.

jacmoe & so0os are right in that the intention is to treat Vector2/Vector3/Vector4 as a data type, maintaining consistency with GPU architectures (shaders); where vectorN is a native data type.

But you're right the documentation could and should be more explicit about this. And certainly doesn't hurt adding it.

By the way there's no default "correct" initialization of a Vector3, because it depends on the intention. When you're working with scales, the "most valid" initialization is Ogre::Vector3::UNIT_SCALE, when you're working with rotations/quaternions the valid initialization is either UNIT_X/UNIT_Y/UNIT_Z or their negative counterparts.
Forcing these explicit initializations helps visualizing the intention and usage of math code. And these initializations are probably more common and used throughout the whole engine than setting everything to zeros.

Cheers
Dark Sylinc
User avatar
sparkprime
Ogre Magi
Posts: 1137
Joined: Mon May 07, 2007 3:43 am
Location: Ossining, New York
x 13

Re: Vector3 member initialization

Post by sparkprime »

It's not actually that uncommon to have a class type that is not fully initialised upon construction. Not preferable, either, of course. I think the style guides need updating and better documentation. Personally I figured it out by reading the source code, which is what I always do when the documentation is unclear.
kneeride
Bugbear
Posts: 807
Joined: Sun May 14, 2006 2:24 pm
Location: Melbourne, Australia

Re: Vector3 member initialization

Post by kneeride »

Hi guys, this topic has come up a number of times. I couldn't find the post but sinbad once said that that this decision was based on performance. Somewhere in the code is a an array of vectors and removing the initialisation improved performance significantly (I assume by avoiding construction on multiple objects). Sinbad had played around with both ideas and decided on handling vectors as a primative type for this reason. Sorry but I couldnt find the post.
jbb
Gnoblar
Posts: 15
Joined: Sun Nov 07, 2004 12:53 pm
x 1

Re: Vector3 member initialization

Post by jbb »

Also, the compiler is often able to warn you that you are reading an uninitialised variable - and tools like purify certainly will.
If you initialise it to anything else, it's almost certainly not the correct value, but you've lost the ability of your tools to warn you about it.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413

Re: Vector3 member initialization

Post by dark_sylinc »

kneeride wrote:Hi guys, this topic has come up a number of times. I couldn't find the post but sinbad once said that that this decision was based on performance. Somewhere in the code is a an array of vectors and removing the initialisation improved performance significantly (I assume by avoiding construction on multiple objects). Sinbad had played around with both ideas and decided on handling vectors as a primative type for this reason. Sorry but I couldnt find the post.
Ahhh yes. I'm not familiar with the original thread, but it gives one of the many examples involving trivial STL operation, in which code can't be optimized by a compiler:

Code: Select all

std::vector<Ogre::Vector3> myArray;
myArray.resize( 1000 );
The compiler can't tell if you, for any chance will later be doing this:

Code: Select all

Ogre::Vector3 *myPtr = &myArray[123];
float x = myPtr->x; //reading uninitialized variable or...
myPtr->x = 120.0f; //...setting variables to valid values, skipping the default ones 
Of course something more sane is to initialize with a loop all 1000 variables. The thing is, the compiler can't know what the heck you will be doing with the heap memory or even with the STL container if it reaches a higher scope (i.e. return value). As a result the compiler can't assume and will always (or at least 99% of cases) initialize those 1.000 vectors.

The resize is just one of many examples. Copy operations often involve constructors, which I'm guessing would be probably the biggest cause of performance slowdowns.

Furthermore Ogre has been expanding to handhelds lately, and compilers for those platforms aren't nearly as advanced as x86 compilers when it comes to optimizations.

My thoughts those guidelines applies mostly to true objects (MaterialManager, Material, Mesh, SubMesh, SceneManager) which by the way aren't initialized that often, and they should have a sane value. But Vector3 acts more as a container of floats, than rather an object IMHO.