Philosophical MOGRE question
So as the title states, my question is a little on the philosophical side. Something along this lines may have already been asked, but I didn't find it with a search, so pardon me if thats the case.
Here's the deal. I am in the process of designing an RPG engine, something akin to the NWN2 engine. Complete with a world authoring tool. I am going to eventually use it to create a small episodic RPG. Here is where the philosophical portion comes in: Would I be doing myself a great disservice in the performance arena if I used MOGRE for the primary engine, and not just the tool set?
Understand, I am very comfortable with C++, but I enjoy programming in C#/.NET more. I find I am more productive and I can focus on the parts of the development process that interest me, namely the problem solving and logic problems. That said, this is meant to be a hobbyist project, so I want to enjoy my time in coding it to the fullest. By the same token, I don't want to end up with an engine that is unable to handle the performance demands of a game. Mind you, I don't plan to use all the latest flashy graphics techniques, but I do plan to do some programmable pipeline stuff: nice water reflections, HDR, things of that nature.
I understand that most of the performance drawbacks presented by MOGRE will come from P/Invoke and having to marshal data between the managed and unmanaged worlds, but it's hard to find real hard data on just how much of a performance hit that causes. Once an assembly is NGen'ed, it's internal code will run pretty fast. I am just curious how much P/Invoke is going to hurt me, and if that degradation in performance is going to really kill the engine. If it's something on the order of 5-10%, I can probably live with that. If it's more than that, I may have to stick with C++ on the game engine side of things.
I haven't done an extensive comparision but the simple test I have done shows no speed difference at all.
The scene consist of 1 single mesh and 1 point light.
Every frame I spin the mesh using the last elapsed frametime.
I ran the scene for 1 minute.
My C++ vc8 version gave me an avg fps of 641.
My VB.Net 2005 version gave me an avg fps of 643.
Now this is a silly comparision but it shows that there doesn't seem to be any noticable performance difference. As soon as you trigger Ogre's automatic renderloop there isn't much "P/Invoking" or marshalling going on.
If I start doing some "heavy" maths with Vectors, Quaternions and such I'm pretty sure I would notice some speed difference but on the other hand Bekas did port these kind of intensively used classes instead of wrapping them just to avoid the P/Invoke overhead.
I'm from the pyOgre camp. In the end i presume we suffer from the same issues, so i'll be so bold as to offer my advice.
Rendering is lightning fast. If you make a tight framelistener you end up running at about C++ speed. What kills you is that, as the game gets more complex, actual game engine logic (managing entities and the relations between them) gets more and more involved. Past some critical point (which is likely further along the way for CLI than it is for python) things explode.
The black art is looking at your project and deciding where it falls along the "explosion line" and decide whether it's safe.
You can get away with pretty awesome things if you don't do anything stupid (like entity proximity calculation based on a O(N^2) algorithm, or O(N) message delivery
) but it's really hard to say a priori without knowing what you are trying to do.
FWIW, i found that all projects that I'm capable of tackling as a one-man team fall squarely in the "do not use C++" bracket, but ymmv ...
You describe my serious game engine to a tee...
I use Mogre for the authoring tool. I am a long-time C++ programmer, but have never used C# or even Java before, so this may be from a perspective different from your own.
The tool came together super fast and was "limping" almost right away. I donated the embedding Mogre in a form demo and Bekas cleaned it up before including it in the package.
As I get deeper into the guts of the tool, I am struggling to make some things work, mostly because of my limited C# "skillz". At this point I am sort of wishing I started in C++, not because C# is bad or anything, its just a comfort zone thing. I find myself looking up all kinds of stuff and taking time to learn how C# does things differently (see my pointer question in this forum).
Meanwhile the runtime engine is going very well and is heavily roadblocked by the tool. I squeak out a feature or bug fix and the engine makes great leaps forward until the next roadblock.
My advice is to think about your comfort zone and stick with it if you are in a time-sensitive production situation. If you are experimenting, try all the new things you can so you have a larger "comfort zone" the next time.
Well, nothing is time sensitive, it's a hobby project...but C#/.NET are within my comfort zone. For instance, your pointer question, I wouldn't need to look up. I've used 'unsafe' code and statements in C# quite a bit, so I've learned to work with fixed pointers and GC handles and such. So I am comfortable I can work past any hurdles pretty easily.
There is no money on the line here, so I think I am going to go with MOGRE even for my main engine. If it ends up being a total failure, well, I've learned a lesson and no one has lost any money. If it ends up working well, then we as a MOGRE community have a completed game engine using MOGRE that we can say "Hey look, you CAN write a real game in C# using MOGRE as long as you understand the environment you are working in".
I doubt that P/Invokes are going to be a performance issue; to be on the safe side, try to avoid method calls (that includes property accesses too, since a property may get/set by calling an Ogre method) on Mogre/Ogre objects inside the time-critical parts of your code (apart from the pure ones
The good thing about C++/CLI is that P/Invokes are kept to the absolute minimum. For example, if you access a int field of an Ogre object, there's no P/Invoke involved, the value is taken by the memory without leaving the managed context.
Also, the compiler inlines most of Ogre methods marked with 'inline' by converting them to CLI code.
Oh, I forgot to mention that the most expensive method calls/property accesses are the ones that involve strings, since these have the biggest marshalling cost.
Why is that? When converting from a managed string to an unmanaged string is such a simple operation?
String^ managedString = "Hello";
size_t convertedChars = 0;
size_t sizeInBytes = 0;
errno_t err = 0;
pin_ptr<const wchar_t> wch_key = PtrToStringChars(managedString);
sizeInBytes = ((managedString->Length + 1) * 2);
char* unmanagedString = (char *)malloc(sizeInBytes);
err = wcstombs_s(&convertedChars, unmanagedString, sizeInBytes, wch_key, sizeInBytes);
Actually it depends a lot on the kind of marshaling you are doing. If you're running this on .net on winxp there should be no big speed impact on the string (just a string memory allocation and a blit), but if you're running MOGRE on lin (in a parallel universe or far future
) or win98, you're going to have a lot of trouble (read as unicode/ansi marshaling).
Another thing that you might need to look at is memory allocations inside those tight loops (no for(int i...) stuff). Doing any operations on a string is a bad idea. Other than that you're going to have no problem at all since the CLR is pretty darn fast.
A test I made which did operate on strings proved to be quite fast. Something like a 2 fps drop. Hardly something worrying.
Anyway, the section about speed issues on the mono homepage might be a little better at dispelling some of the clouds on any c++ speed freak's sky. Quite a lot of time has passed since c++ came on the block so some of the things are done quite differently in the CLI world. Doing them the c++ way is a shore-fire and sadistic way of creating an app that can ron on par with windows vista when it comes to resource hogging.
If you're running this on .net on winxp there should be no big speed impact on the string (just a string memory allocation and a blit), but if you're running MOGRE on lin (in a parallel universe or far future ) or win98, you're going to have a lot of trouble (read as unicode/ansi marshaling).
Unfortunately, Ogre's strings are ansi strings, so there's the unicode/ansi marshaling in WinXP as well.
If someone goes over the Ogre source and turn all the strings to unicode then it's going to be "just a string memory allocation and a blit".